Go با مثال: اسلایس‌ها

اسلایس‌ها (slices) نوع داده‌ی مهمی در Go هستند و رابطی قدرتمندتر از آرایه‌ها برای کار با دنباله‌ها فراهم می‌کنند.

package main
import (
    "fmt"
    "slices"
)
func main() {

برخلاف آرایه‌ها، نوع اسلایس فقط به نوع عناصرش بستگی دارد (نه به تعداد عناصر). اسلایسی که مقداردهی نشده برابر با nil است و طول آن 0 است.

    var s []string
    fmt.Println("uninit:", s, s == nil, len(s) == 0)

برای ساختن اسلایسی با طول غیرصفر، از تابع داخلی make استفاده کنید. اینجا یک اسلایس از stringها با طول 3 می‌سازیم (که در ابتدا مقدار صفر دارند). به‌طور پیش‌فرض ظرفیت (capacity) یک اسلایس جدید برابر طول آن است؛ اگر از قبل بدانیم اسلایس بزرگ‌تر خواهد شد، می‌توانیم ظرفیت را صریحاً به‌عنوان پارامتر اضافه به make بدهیم.

    s = make([]string, 3)
    fmt.Println("emp:", s, "len:", len(s), "cap:", cap(s))

مقداردهی و خواندن درست مثل آرایه‌هاست.

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("set:", s)
    fmt.Println("get:", s[2])

همان‌طور که انتظار دارید، len طول اسلایس را برمی‌گرداند.

    fmt.Println("len:", len(s))

علاوه بر این عملیات پایه، اسلایس‌ها از عملیات دیگری هم پشتیبانی می‌کنند که آن‌ها را از آرایه‌ها کاربردی‌تر می‌کند. یکی از آن‌ها تابع داخلی append است که اسلایسی شامل یک یا چند مقدار جدید برمی‌گرداند. توجه کنید که باید مقدار بازگشتی append را دریافت کنیم، چون ممکن است یک اسلایس جدید برگردد.

    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("apd:", s)

اسلایس‌ها را می‌توان با copy کپی کرد. اینجا اسلایس خالی c را با همان طول s می‌سازیم و s را در c کپی می‌کنیم.

    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("cpy:", c)

اسلایس‌ها از عملگر «برش» با نحو slice[low:high] پشتیبانی می‌کنند. برای مثال، این کد اسلایسی از عناصر s[2]، s[3] و s[4] می‌گیرد.

    l := s[2:5]
    fmt.Println("sl1:", l)

این یکی تا s[5] برش می‌زند (خود s[5] شامل نمی‌شود).

    l = s[:5]
    fmt.Println("sl2:", l)

و این یکی از s[2] (با خودش) به بعد برش می‌زند.

    l = s[2:]
    fmt.Println("sl3:", l)

می‌توانیم یک متغیر اسلایس را در یک خط تعریف و مقداردهی هم بکنیم.

    t := []string{"g", "h", "i"}
    fmt.Println("dcl:", t)

بستهٔ slices تعدادی تابع کمکی مفید برای اسلایس‌ها دارد.

    t2 := []string{"g", "h", "i"}
    if slices.Equal(t, t2) {
        fmt.Println("t == t2")
    }

اسلایس‌ها را می‌توان برای ساختن ساختارهای داده‌ی چندبعدی ترکیب کرد. برخلاف آرایه‌های چندبعدی، طول اسلایس‌های داخلی می‌تواند متفاوت باشد.

    twoD := make([][]int, 3)
    for i := range 3 {
        innerLen := i + 1
        twoD[i] = make([]int, innerLen)
        for j := range innerLen {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}

توجه کنید که با اینکه نوع اسلایس‌ها با آرایه‌ها فرق دارد، fmt.Println آن‌ها را شبیه هم نمایش می‌دهد.

$ go run slices.go
uninit: [] true true
emp: [  ] len: 3 cap: 3
set: [a b c]
get: c
len: 3
apd: [a b c d e f]
cpy: [a b c d e f]
sl1: [c d e]
sl2: [a b c d e]
sl3: [c d e f]
dcl: [g h i]
t == t2
2d:  [[0] [1 2] [2 3 4]]

برای جزئیات بیشتر دربارهٔ طراحی و پیاده‌سازی اسلایس‌ها در Go، این مقالهٔ عالی از تیم Go را بخوانید.

حالا که آرایه‌ها و اسلایس‌ها را دیدیم، سراغ ساختار داده‌ی داخلی کلیدی دیگر Go می‌رویم: مپ‌ها.

مثال بعدی: .