1 مقدمه‌ای درباره انواع داده‌های زبان Go

در زبان Go، انواع داده مبنای برنامه نویسی را تشکیل می‌دهند و شکل داده‌هایی که متغیرها می‌توانند ذخیره کنند را تعیین می‌کنند. انواع داده اصلی ارائه شده توسط زبان Go به‌صورت اصلی در دسته‌های زیر تقسیم می‌شوند:

نوع داده توضیحات استفاده از حافظه
bool نوع داده بولیایی، برای ذخیره سازی مقادیر درست یا غلط استفاده می‌شود 1 بایت
int، uint اعداد صحیح با نشان منفی و بدون نشان، اندازه پیش‌فرض به بستگی به پلتفرم سیستم است 4 یا 8 بایت
int8، uint8 اعداد صحیح 8 بیتی با نشان منفی و بدون نشان 1 بایت
int16، uint16 اعداد صحیح 16 بیتی با نشان منفی و بدون نشان 2 بایت
int32، uint32 اعداد صحیح 32 بیتی با نشان منفی و بدون نشان 4 بایت
int64، uint64 اعداد صحیح 64 بیتی با نشان منفی و بدون نشان 8 بایت
float32 عدد ممیز شناور 32 بیتی 4 بایت
float64 عدد ممیز شناور 64 بیتی 8 بایت
complex64 عدد مختلط با بخش حقیقی 32 بیتی و بخش تخیلی 32 بیتی 8 بایت
complex128 عدد مختلط با بخش حقیقی 64 بیتی و بخش تخیلی 64 بیتی 16 بایت
byte مشابه uint8 1 بایت
rune مشابه int32، نمایانگر یک نقطه کد یونیکد 4 بایت
string نوع رشته به طول رشته بستگی دارد
error رابط خطا، برای بازگرداندن اطلاعات خطا استفاده می‌شود بدون اندازه ثابت

این انواع بر اساس نیازهای مختلف مانند محاسبات عددی، پردازش متنی یا کنترل منطقی انتخاب می‌شوند.

2 انواع داده‌های صحیح

2.1 مروری بر انواع داده‌های صحیح

زبان Go دارای چندین نوع داده صحیح داخلی است که به‌صورت زیر دسته‌بندی می‌شوند:

  • اعداد صحیح نشان‌دار: int8، int16، int32 (یا rune)، int64 و int
  • اعداد صحیح بدون نشان: uint8 (یا byte)، uint16، uint32، uint64 و uint

اندازه‌های int و uint بر روی سیستم‌های 32 بیتی 4 بایت و بر روی سیستم‌های 64 بیتی 8 بایت هستند. محدوده‌های مقادیر انواع داده صحیح در جدول زیر نشان داده شده‌اند:

نوع محدوده مقادیر
int8 -128 تا 127
uint8 0 تا 255
int16 -32768 تا 32767
uint16 0 تا 65535
int32 -2147483648 تا 2147483647
uint32 0 تا 4294967295
int64 -9223372036854775808 تا 9223372036854775807
uint64 0 تا 18446744073709551615

2.2 استفاده از متغیرهای صحیح

دستورات اصلی برای اعلام یک متغیر صحیح به‌صورت زیر است:

var نام_متغیر نوع_داده = مقدار_اولیه

کد نمونه:

package main
import "fmt"

func main() {
    var a int = 10 // متغیر صحیح نشان‌دار
    var b uint = 20 // متغیر صحیح بدون نشان
    var c int8 = -128 // کوچک‌ترین مقدار int8
    fmt.Println(a, b, c)
}

2.3 عملیات صحیح

زبان Go از عملگرهای اصلی حسابی پشتیبانی می‌کند، مانند جمع (+)، تفریق (-)، ضرب (×)، تقسیم (÷) و باقی‌مانده تقسیم (%)، همچنین از عملگرهای بیتی مانند AND بیتی (&)، OR بیتی (|)، XOR بیتی (^)، انتقال چپ (<<) و انتقال راست (>>) پشتیبانی می‌کند.

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // عملیات حسابی
    fmt.Println(x + y) // جمع
    fmt.Println(x - y) // تفریق
    fmt.Println(x * y) // ضرب
    fmt.Println(x / y) // تقسیم
    fmt.Println(x % y) // باقی‌مانده تقسیم

    // عملیات بیتی
    fmt.Println(x & y)  // AND بیتی
    fmt.Println(x | y)  // OR بیتی
    fmt.Println(x ^ y)  // XOR بیتی
    fmt.Println(x << 1) // انتقال چپ یک بیت
    fmt.Println(x >> 1) // انتقال راست یک بیت
}

3 انواع داده‌های عدد ممیز شناور

3.1 بررسی کلی انواع داده‌های نقطه‌شناور

در زبان Go، انواع نقطه‌شناور شامل float32 و float64 هستند که به ترتیب متناظر با داده‌های نقطه‌شناور 32 بیتی و 64 بیتی هستند. به طور کلی، توصیه می‌شود از float64 استفاده شود زیرا دامنه بزرگتری ارائه می‌دهد و دقت دقیق‌تری دارد.

  • float32 حدود 23 بیت مهم دارد که حدود 7 رقم اعشاری دقت ارائه می‌دهد.
  • float64 حدود 52 بیت مهم دارد که حدود 16 رقم اعشاری دقت ارائه می‌دهد.

3.2 استفاده از متغیرهای نقطه‌شناور

متغیرهای نقطه‌شناور می‌توانند با ارائه مستقیم اعداد یا با استفاده از کلمه کلیدی var اعلان شوند:

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // نوع float32 به صورت صریح مشخص شده است
    f2 := 3.14            // به طور خودکار به عنوان نوع float64 استنتاج می‌شود
    fmt.Println(f1, f2)
}

3.3 حساب عملیات نقطه‌شناوری و مسائل مربوطه

حساب عملیات نقطه‌شناوری ممکن است منجر به از دست دادن دقت شود. انجام عملیات با دقت بسیار بالا یک مسأله رایج است، به ویژه زمانی که دو عدد بسیار نزدیک از یکدیگر کم شود.

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // خروجی ممکن است به علت مسئله دقت، .3 مورد انتظار نباشد

    // رفع مشکل دقت با استفاده از خروجی قالب‌بندی شده
    fmt.Printf("%.1f\n", f3) // خروجی به .3 اصلاح شده است
}

4 نوع داده‌ای منطقی

4.1 بررسی کلی نوع داده‌ای منطقی

منطقی (Boolean) ساده‌ترین نوع داده است و تنها دو مقدار true (درست) و false (غلط) می‌تواند داشته باشد. این نوع در بیانیه‌های شرطی و ساختارهای کنترل حلقه‌ها جایگاه بسیار مهمی دارد.

4.2 استفاده از متغیرهای منطقی

اعلان و استفاده از متغیرهای منطقی:

package main
import "fmt"

func main() {
    var success bool = true
    var fail bool = false
    fmt.Println("عملیات موفقیت‌آمیز بود:", success)
    fmt.Println("عملیات ناموفق بود:", fail)
}

مقادیر منطقی اغلب در بیانیه‌های شرطی استفاده می‌شوند:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // false
    fmt.Println("a < b:", a < b)   // true
}

5 نوع داده‌ای رشته

5.1 بررسی کلی رشته

رشته مجموعه‌ای از حروف است. در زبان Go، رشته‌ها غیرقابل تغییرند. هر رشته از دو بخش تشکیل شده است: یک اشاره‌گر به آرایه بایت مبنایی و یک طول. رشته‌ها می‌توانند هرگونه داده‌ای را شامل شوند، از جمله بایت‌ها.

5.2 استفاده از متغیرهای رشته

متغیرهای رشته معمولاً با استفاده از نقل قول دوتایی " تعریف می‌شوند، اما می‌توانید از نقل قول بکتیک \ برای ایجاد رشته‌های چندخطه استفاده کنید:

package main
import "fmt"

func main() {
    var s1 string = "سلام"
    s2 := "دنیا"
    s3 := `این یک
    رشته چندخطه است`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

هنگامی که یک رشته ایجاد شود، محتوای آن نمی‌تواند تغییر یابد. عملیات زیر غیرمجاز است و منجر به خطای ترکیب‌سازی می‌شود:

s := "سلام"
s[] = 'ح` // خطای ترکیب‌سازی: محتوای رشته غیرقابل تغییر است

5.3 عملیات رشته‌ای

رشته‌ها بسیار رایج و مهم در برنامه‌نویسی هستند. زبان Go مجموعه‌ای غنی از توابع تعبیه‌شده برای دستکاری رشته‌ها ارائه می‌دهد. در زیر چند عملیات معمول استفاده‌شده آورده شده است.

5.3.1 ادغام رشته‌ها

در زبان Go، می‌توانید از عملگر چند (+) برای ادغام رشته‌ها استفاده کنید که ساده‌ترین روش است. علاوه بر این، زمانی که با ادغام مکرر چند رشته سر و کار داشته باشید، توصیه می‌شود از strings.Builder برای عملکرد بهتر استفاده کنید.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // ادغام رشته‌ها با استفاده از +
    hello := "سلام، "
    world := "دنیا!"
    result := hello + world
    fmt.Println(result) // خروجی: سلام، دنیا!

    // ادغام رشته‌ها با استفاده از strings.Builder
    var sb strings.Builder
    sb.WriteString("سلام، ")
    sb.WriteString("دنیا!")
    fmt.Println(sb.String()) // خروجی: سلام، دنیا!
}

5.3.2 تقسیم رشته‌ها

برای انجام عملیات تقسیم رشته‌ها می‌توان از تابع strings.Split استفاده کرد که رشته را بر اساس جداکننده مشخص شده به یک آرایه تقسیم می‌کند.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // تعریف یک رشته
    sentence := "Go زبان برنامه نویسی منبع بازی است"

    // تقسیم رشته بر اساس فاصله
    words := strings.Split(sentence, " ")
    for _, word := range words {
        fmt.Printf("%s\n", word)
    }
    // خروجی:
    // Go
    // زبان
    // برنامه
    // نویسی
    // منبع
    // بازی
    // است
}

5.3.3 دسترسی به اندیس

در Go، یک رشته یک دنباله ثابت از بایت‌ها است. می‌توانید از اندیس‌گذاری برای دسترسی به بایت‌های مشخص در یک رشته استفاده کنید. با این حال، مهم است که توجه داشته باشید اگرچه یک رشته ممکن است شامل کاراکترهای چند بایتی (مانند کاراکترهای UTF-8) باشد، استفاده مستقیم از اندیس‌گذاری ممکن است کاراکتر تکی مورد انتظار را ندهد.

package main

import "fmt"

func main() {
    s := "سلام، 世界"
    for i := 0; i < len(s); i++ {
        fmt.Printf("%d: %x\n", i, s[i])
    }
    // توجه: این خروجی نمایش می‌دهد نمایش می‌دهد نمایش هگزادسیمال بایت‌ها برابر با کاراکترها نمی‌باشد
}

برای گردش از طریق رشته بر اساس کاراکتر می‌توانید از حلقه range استفاده کنید.

package main

import "fmt"

func main() {
    s := "سلام، 世界"
    for index, runeValue := range s {
        fmt.Printf("%d: %U '%c'\n", index, runeValue, runeValue)
    }
    // خروجی: اندیس، کد یونیکد و خود کاراکتر برای هر کاراکتر
}

5.3.4 دریافت طول

تابع len می‌تواند طول یک رشته را بدست آورد، به معنای طول دنباله بایتی زیرین. برای رشته‌های UTF-8، اگر نیاز دارید تا تعداد کاراکترها (ران‌ها) را بدست آورید، باید از تابع utf8.RuneCountInString استفاده کنید. این تابع قادر است به درستی با کاراکترهای چند بایتی رخداد را انجام دهد.

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "سلام، 世界"
    fmt.Println("طول بایت‌ها:", len(s)) // نمایش طول بایتی
    fmt.Println("طول ران‌ها:", utf8.RuneCountInString(s)) // نمایش طول کاراکتری
}

از مثال بالا می‌توان دید که زبان Go امکانات غنی برای عملیات روی رشته ارائه داده‌است، که انجام وظایف مختلف پردازش رشته را آسان می‌کند. هنگام کدنویسی، مهم است که به تفاوت بین بایت‌ها و کاراکترها توجه کنید، به خصوص زمانی که با مجموعه‌های کاراکتری غیر-ASCII سروکار دارید.