GoCasts آموزش Go به زبان ساده

بیش از ۱۰۰۰ شرکت‌کننده یادگیری Go و Backend رو از امروز شروع کن
ثبت‌نام دوره + تیم‌سازی

انواع داده در گولنگ - آموزش متغیرها و تایپ‌ها در Go

درک انواع داده یکی از اساسی‌ترین مفاهیم در هر زبان برنامه‌نویسی است. Go یک زبان strongly typed است، یعنی هر متغیر باید نوع مشخصی داشته باشد. در این مقاله، تمام انواع داده در Go را با مثال‌های عملی بررسی می‌کنیم.

تعریف متغیر در Go

قبل از بررسی انواع داده، باید با روش‌های تعریف متغیر آشنا شویم:

روش ۱: تعریف کامل با var

var name string = "علی"
var age int = 25
var price float64 = 19.99
var isActive bool = true

روش ۲: استنتاج نوع (Type Inference)

var name = "علی"    // Go خودش تشخیص می‌دهد: string
var age = 25        // int
var price = 19.99   // float64

روش ۳: تعریف کوتاه با :=

name := "علی"       // فقط داخل توابع کار می‌کند
age := 25
price := 19.99

روش ۴: تعریف چندگانه

var (
    name    string = "علی"
    age     int    = 25
    isAdmin bool   = false
)

// یا
x, y, z := 1, 2, 3

انواع داده پایه (Basic Types)

۱. اعداد صحیح (Integers)

Go انواع مختلفی از اعداد صحیح دارد:

نوع اندازه محدوده
int8 8 بیت -128 تا 127
int16 16 بیت -32,768 تا 32,767
int32 32 بیت -2.1 میلیارد تا 2.1 میلیارد
int64 64 بیت -9.2 کوینتیلیون تا 9.2 کوینتیلیون
int 32 یا 64 بیت بستگی به سیستم

اعداد صحیح بدون علامت (Unsigned):

نوع اندازه محدوده
uint8 (byte) 8 بیت 0 تا 255
uint16 16 بیت 0 تا 65,535
uint32 32 بیت 0 تا 4.2 میلیارد
uint64 64 بیت 0 تا 18.4 کوینتیلیون
package main

import "fmt"

func main() {
    var a int = 42
    var b int8 = 127
    var c uint = 100
    var d byte = 255  // معادل uint8

    fmt.Printf("a: %d (type: %T)\n", a, a)
    fmt.Printf("b: %d (type: %T)\n", b, b)
    fmt.Printf("c: %d (type: %T)\n", c, c)
    fmt.Printf("d: %d (type: %T)\n", d, d)
}

نکته: در بیشتر موارد از int استفاده کنید. فقط وقتی به بهینه‌سازی حافظه نیاز دارید، نوع دقیق را مشخص کنید.

۲. اعداد اعشاری (Floating Point)

نوع اندازه دقت
float32 32 بیت ~7 رقم اعشار
float64 64 بیت ~15 رقم اعشار
package main

import (
    "fmt"
    "math"
)

func main() {
    var pi float64 = 3.14159265358979
    var e float32 = 2.71828

    fmt.Printf("pi = %.10f\n", pi)
    fmt.Printf("e = %.5f\n", e)

    // اعداد خاص
    inf := math.Inf(1)      // بی‌نهایت مثبت
    nan := math.NaN()       // Not a Number

    fmt.Printf("Infinity: %f\n", inf)
    fmt.Printf("NaN: %f\n", nan)
}

نکته: همیشه از float64 استفاده کنید مگر اینکه دلیل خاصی برای float32 داشته باشید.

۳. اعداد مختلط (Complex Numbers)

var c1 complex64 = 3 + 4i
var c2 complex128 = complex(5, 12)

fmt.Println(c1)           // (3+4i)
fmt.Println(real(c2))     // 5
fmt.Println(imag(c2))     // 12

۴. بولین (Boolean)

var isActive bool = true
var isAdmin bool = false

// عملگرهای منطقی
fmt.Println(true && false)   // false (AND)
fmt.Println(true || false)   // true (OR)
fmt.Println(!true)           // false (NOT)

// مقایسه
x, y := 5, 10
fmt.Println(x < y)           // true
fmt.Println(x == y)          // false
fmt.Println(x != y)          // true

۵. رشته (String)

رشته‌ها در Go immutable هستند، یعنی پس از ایجاد قابل تغییر نیستند.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // تعریف رشته
    name := "سلام دنیا"
    greeting := `این یک
    رشته چند خطی
    است`

    // طول رشته (تعداد بایت)
    fmt.Println(len(name))          // 17 (UTF-8 bytes)

    // تعداد کاراکترها
    fmt.Println(len([]rune(name)))  // 9

    // الحاق رشته
    fullName := "علی" + " " + "رضایی"
    fmt.Println(fullName)

    // توابع کاربردی
    s := "Hello, World!"
    fmt.Println(strings.ToUpper(s))         // HELLO, WORLD!
    fmt.Println(strings.ToLower(s))         // hello, world!
    fmt.Println(strings.Contains(s, "World")) // true
    fmt.Println(strings.Replace(s, "World", "Go", 1))
    fmt.Println(strings.Split(s, ", "))     // [Hello World!]
}

۶. Rune

rune معادل int32 است و برای نمایش یک کاراکتر Unicode استفاده می‌شود:

package main

import "fmt"

func main() {
    var r rune = 'ا'  // حرف الف فارسی
    fmt.Printf("%c = %d\n", r, r)  // ا = 1575

    // پیمایش روی رشته فارسی
    text := "سلام"
    for i, char := range text {
        fmt.Printf("Index: %d, Char: %c, Code: %d\n", i, char, char)
    }
}

انواع داده مرکب (Composite Types)

۱. آرایه (Array)

آرایه‌ها طول ثابت دارند و نوع عناصر یکسان است:

package main

import "fmt"

func main() {
    // تعریف آرایه
    var numbers [5]int                    // [0 0 0 0 0]
    var names [3]string = [3]string{"علی", "رضا", "مریم"}
    scores := [4]int{90, 85, 78, 92}
    auto := [...]int{1, 2, 3, 4, 5}       // طول خودکار

    // دسترسی و تغییر
    numbers[0] = 10
    fmt.Println(numbers[0])  // 10

    // طول آرایه
    fmt.Println(len(scores)) // 4

    // پیمایش
    for i, name := range names {
        fmt.Printf("%d: %s\n", i, name)
    }

    // آرایه دو بعدی
    matrix := [2][3]int{
        {1, 2, 3},
        {4, 5, 6},
    }
    fmt.Println(matrix[1][2]) // 6
}

۲. برش (Slice)

Slice‌ها آرایه‌های پویا هستند و بیشترین استفاده را دارند:

package main

import "fmt"

func main() {
    // ایجاد slice
    var s1 []int                          // nil slice
    s2 := []int{1, 2, 3, 4, 5}           // با مقدار اولیه
    s3 := make([]int, 5)                  // طول 5، ظرفیت 5
    s4 := make([]int, 3, 10)              // طول 3، ظرفیت 10

    fmt.Printf("s1: %v, len=%d, cap=%d\n", s1, len(s1), cap(s1))
    fmt.Printf("s2: %v, len=%d, cap=%d\n", s2, len(s2), cap(s2))

    // اضافه کردن عنصر
    s1 = append(s1, 1, 2, 3)
    fmt.Println(s1)  // [1 2 3]

    // برش از slice
    sub := s2[1:4]   // [2 3 4]
    fmt.Println(sub)

    // کپی
    dst := make([]int, len(s2))
    copy(dst, s2)

    // حذف عنصر (ایندکس 2)
    s2 = append(s2[:2], s2[3:]...)
    fmt.Println(s2)  // [1 2 4 5]
}

۳. نقشه (Map)

Map‌ها ساختار داده کلید-مقدار هستند:

package main

import "fmt"

func main() {
    // ایجاد map
    var m1 map[string]int                           // nil map
    m2 := map[string]int{"علی": 25, "رضا": 30}     // با مقدار
    m3 := make(map[string]int)                      // خالی

    // اضافه کردن
    m3["مریم"] = 28
    m3["زهرا"] = 22

    // دسترسی
    age := m2["علی"]
    fmt.Println(age)  // 25

    // بررسی وجود کلید
    value, exists := m2["حسن"]
    if exists {
        fmt.Println(value)
    } else {
        fmt.Println("کلید وجود ندارد")
    }

    // حذف
    delete(m2, "علی")

    // پیمایش
    for key, value := range m3 {
        fmt.Printf("%s: %d\n", key, value)
    }

    // طول
    fmt.Println(len(m3))
}

۴. ساختار (Struct)

Struct‌ها برای گروه‌بندی داده‌های مرتبط استفاده می‌شوند:

package main

import "fmt"

// تعریف struct
type Person struct {
    Name    string
    Age     int
    Email   string
    IsAdmin bool
}

// struct تو در تو
type Company struct {
    Name      string
    CEO       Person
    Employees []Person
}

func main() {
    // ایجاد نمونه
    p1 := Person{
        Name:    "علی رضایی",
        Age:     30,
        Email:   "ali@example.com",
        IsAdmin: true,
    }

    // دسترسی به فیلدها
    fmt.Println(p1.Name)
    p1.Age = 31

    // ایجاد با ترتیب
    p2 := Person{"رضا", 25, "reza@example.com", false}

    // اشاره‌گر به struct
    p3 := &Person{Name: "مریم", Age: 28}
    fmt.Println(p3.Name)  // نیازی به *p3.Name نیست

    // struct ناشناس
    point := struct {
        X, Y int
    }{10, 20}
    fmt.Println(point)

    // struct تو در تو
    company := Company{
        Name: "شرکت نمونه",
        CEO:  p1,
        Employees: []Person{p2},
    }
    fmt.Println(company.CEO.Name)
}

تبدیل نوع (Type Conversion)

Go تبدیل خودکار نوع ندارد و باید صریحاً انجام شود:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // عدد به عدد
    var i int = 42
    var f float64 = float64(i)
    var u uint = uint(i)

    fmt.Printf("int: %d, float64: %f, uint: %d\n", i, f, u)

    // عدد به رشته
    s1 := strconv.Itoa(42)           // "42"
    s2 := fmt.Sprintf("%d", 42)      // "42"
    s3 := strconv.FormatFloat(3.14, 'f', 2, 64)  // "3.14"

    fmt.Println(s1, s2, s3)

    // رشته به عدد
    n1, _ := strconv.Atoi("42")             // 42
    n2, _ := strconv.ParseFloat("3.14", 64) // 3.14
    n3, _ := strconv.ParseBool("true")      // true

    fmt.Println(n1, n2, n3)

    // رشته به بایت و برعکس
    bytes := []byte("سلام")
    str := string(bytes)
    fmt.Println(str)
}

مقدار صفر (Zero Value)

در Go، متغیرهای تعریف‌شده بدون مقدار اولیه، مقدار صفر می‌گیرند:

نوع مقدار صفر
int, float 0
bool false
string "" (رشته خالی)
pointer, slice, map, channel, func nil
var i int       // 0
var f float64   // 0.0
var b bool      // false
var s string    // ""
var p *int      // nil
var sl []int    // nil
var m map[string]int  // nil

Type Alias و Type Definition

// Type Definition - نوع جدید
type UserID int
type Username string

// Type Alias - فقط نام جدید
type ID = int

func main() {
    var uid UserID = 100
    var id ID = 100

    // uid و int تایپ متفاوت هستند
    // var x int = uid  // خطا!
    var x int = int(uid) // درست

    // id و int یکی هستند
    var y int = id       // درست
}

جمع‌بندی

دسته انواع کاربرد
اعداد صحیح int, int8-64, uint, uint8-64 شمارش، ایندکس
اعداد اعشاری float32, float64 محاسبات علمی، قیمت
بولین bool شرط‌ها، فلگ‌ها
رشته string متن، داده‌های متنی
آرایه [n]T داده با طول ثابت
Slice []T لیست‌های پویا
Map map[K]V جستجوی سریع
Struct struct{} داده‌های ساختاریافته

قدم‌های بعدی

منابع

بیش از ۱۰۰۰ شرکت‌کننده یادگیری Go و Backend رو از امروز شروع کن
ثبت‌نام دوره + تیم‌سازی