Goku

داده‌ساختارها و مدیریت حافظه در زبان برنامه‌نویسی Go

این جزوه به بررسی داده‌ساختارهای اصلی در Go (آرایه‌ها، اسلایس‌ها، مپ‌ها، رشته‌ها، ساختارها، و رابط‌ها) و مدیریت حافظه (اشاره‌گرها، garbage collection، و بهینه‌سازی) می‌پردازد. هر بخش با توضیحات مفهومی، مثال‌های عملی، نکات پیشرفته، و خطاهای رایج همراه است.


1. داده‌ساختارها در Go

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

1.1. آرایه‌ها (Arrays)

تعریف

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

سینتکس

var arr [3]int // آرایه‌ای با 3 عدد صحیح
arr := [3]int{1, 2, 3} // مقداردهی مستقیم

ویژگی‌ها

مثال

package main

import "fmt"

func main() {
    var arr [4]int
    arr[0] = 10
    arr[1] = 20
    fmt.Println(arr) // خروجی: [10 20 0 0]

    arr2 := [3]string{"Ali", "Bob", "Cathy"}
    for i, v := range arr2 {
        fmt.Printf("Index: %d, Value: %s\n", i, v)
    }
}

نکات پیشرفته

خطاهای رایج


1.2. اسلایس‌ها (Slices)

تعریف

اسلایس یک نمای پویا از یک آرایه است که اندازه آن می‌تواند تغییر کند. اسلایس‌ها پرکاربردترین داده‌ساختار در Go هستند.

سینتکس

var slice []int // اسلایس خالی
slice := []int{1, 2, 3} // مقداردهی مستقیم
slice := make([]int, 5, 10) // طول 5، ظرفیت 10

ساختار داخلی

اسلایس شامل سه بخش است:

  1. اشاره‌گر: به آرایه زیرین اشاره می‌کند.
  2. طول (Length): تعداد عناصر فعلی.
  3. ظرفیت (Capacity): تعداد عناصری که آرایه زیرین می‌تواند نگه دارد.

عملیات اصلی

مثال

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3}
    slice = append(slice, 4, 5)
    fmt.Println("Slice:", slice) // خروجی: [1 2 3 4 5]

    fmt.Println("Length:", len(slice)) // 5
    fmt.Println("Capacity:", cap(slice)) // 5 یا بیشتر

    subSlice := slice[1:4]
    fmt.Println("Subslice:", subSlice) // [2 3 4]

    // تغییر در subSlice روی slice اصلی اثر می‌گذارد
    subSlice[0] = 99
    fmt.Println("Original after change:", slice) // [1 99 3 4 5]
}

نکات پیشرفته

خطاهای رایج


1.3. مپ‌ها (Maps)

تعریف

مپ یک داده‌ساختار کلید-مقدار است که برای ذخیره و بازیابی سریع داده‌ها استفاده می‌شود.

سینتکس

var m map[string]int // مپ خالی (nil)
m := make(map[string]int) // مپ آماده
m := map[string]int{"Ali": 30, "Bob": 25} // مقداردهی مستقیم

عملیات اصلی

مثال

package main

import "fmt"

func main() {
    m := make(map[string]int)
    m["Ali"] = 30
    m["Bob"] = 25

    fmt.Println("Map:", m) // خروجی: map[Ali:30 Bob:25]

    age, exists := m["Ali"]
    if exists {
        fmt.Println("Age of Ali:", age) // 30
    }

    delete(m, "Bob")
    fmt.Println("After delete:", m) // map[Ali:30]
}

نکات پیشرفته

خطاهای رایج


1.4. رشته‌ها و Rune

تعریف

رشته‌ها در Go دنباله‌ای از بایت‌ها هستند که معمولاً به صورت UTF-8 ذخیره می‌شوند. نوع rune برای نمایش کاراکترهای یونیکد استفاده می‌شود (معادل int32).

سینتکس

s := "Hello, جهان"
r := rune('ج') // یک کاراکتر یونیکد

عملیات

مثال

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Hello, جهان"
    fmt.Println("Length in bytes:", len(s)) // تعداد بایت‌ها
    fmt.Println("Length in runes:", utf8.RuneCountInString(s)) // تعداد کاراکترها

    for i, r := range s {
        fmt.Printf("Index: %d, Rune: %c\n", i, r)
    }

    // تبدیل به rune
    runes := []rune(s)
    fmt.Println("First rune:", string(runes[0])) // H
}

نکات پیشرفته

خطاهای رایج


1.5. ساختارها (Structs)

تعریف

ساختارها برای تعریف داده‌های پیچیده با چندین فیلد استفاده می‌شوند.

سینتکس

type Person struct {
    Name string
    Age  int
}

عملیات

مثال

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func (p Person) Greet() string {
    return fmt.Sprintf("Hello, %s! You are %d years old.", p.Name, p.Age)
}

func main() {
    p := Person{Name: "Ali", Age: 30}
    fmt.Println(p.Greet()) // Hello, Ali! You are 30 years old.

    // اشاره‌گر به struct
    pp := &p
    pp.Age = 31
    fmt.Println(p.Age) // 31
}

نکات پیشرفته

خطاهای رایج


1.6. رابط‌ها (Interfaces)

تعریف

رابط‌ها مجموعه‌ای از متدها را تعریف می‌کنند که یک نوع باید پیاده‌سازی کند.

سینتکس

type Shape interface {
    Area() float64
}

پیاده‌سازی

هر نوع که متدهای رابط را پیاده‌سازی کند، به طور خودکار آن رابط را ارضا می‌کند.

مثال

package main

import (
    "fmt"
    "math"
)

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func printArea(s Shape) {
    fmt.Printf("Area: %.2f\n", s.Area())
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 4, Height: 6}

    printArea(c) // Area: 78.54
    printArea(r) // Area: 24.00
}

نکات پیشرفته

خطاهای رایج


2. مدیریت حافظه در Go

Go دارای سیستم مدیریت حافظه خودکار (garbage collection) است، اما درک اشاره‌گرها و بهینه‌سازی حافظه برای نوشتن برنامه‌های کارآمد ضروری است.

2.1. اشاره‌گرها (Pointers)

تعریف

اشاره‌گر متغیری است که آدرس حافظه یک متغیر دیگر را ذخیره می‌کند.

سینتکس

var p *int // اشاره‌گر به int
x := 42
p = &x // آدرس x
*p = 43 // تغییر مقدار

مثال

package main

import "fmt"

func increment(p *int) {
    *p++
}

func main() {
    x := 42
    increment(&x)
    fmt.Println(x) // 43
}

نکات پیشرفته

خطاهای رایج


2.2. Garbage Collection

تعریف

Go از یک garbage collector (GC) برای مدیریت حافظه استفاده می‌کند که اشیاء غیرقابل دسترس را آزاد می‌کند.

نحوه کار

بهینه‌سازی

نکات پیشرفته

خطاهای رایج


2.3. بهینه‌سازی حافظه

تکنیک‌ها

مثال

package main

import (
    "fmt"
    "strings"
)

func main() {
    var builder strings.Builder
    for i := 0; i < 1000; i++ {
        builder.WriteString("x")
    }
    fmt.Println("Length:", builder.Len())
}

نکات پیشرفته


3. بهترین شیوه‌ها و نکات


4. نتیجه‌گیری

این جزوه داده‌ساختارهای اصلی Go (آرایه‌ها، اسلایس‌ها، مپ‌ها، رشته‌ها، ساختارها، و رابط‌ها) و مدیریت حافظه (اشاره‌گرها، garbage collection، و بهینه‌سازی) را با جزئیات کامل پوشش داد. هر بخش با مثال‌های عملی، نکات پیشرفته، و خطاهای رایج همراه بود تا درک عمیقی از این مفاهیم فراهم شود.

برای یادگیری بیشتر: