Arrays, Slices และ Maps
Collections: จาก array ของ JS สู่ slice ของ Go
หัวข้อที่มีชื่อว่า “Collections: จาก array ของ JS สู่ slice ของ Go”ใน JavaScript/TypeScript array เป็นแบบไดนามิกโดยปริยาย และ object ทำหน้าที่เป็น map ส่วน Go แยกเรื่องเหล่านี้ออกจากกัน: arrays ขนาดคงที่, slices แบบไดนามิก (ตัวที่คุณจะใช้ทุกวัน) และ maps
Arrays เทียบกับ Slices
หัวข้อที่มีชื่อว่า “Arrays เทียบกับ Slices”array ของ Go มีขนาดคงที่ฝังอยู่ใน type เลย ในทางปฏิบัติคุณแทบไม่ได้ใช้ array ตรง ๆ ตัวที่ใช้จริงคือ slice — เวอร์ชันไดนามิกที่มี array หนุนอยู่เบื้องหลัง แต่มี length และ capacity ที่ขยายได้ตามต้องการ
// TypeScript — always dynamicconst nums: number[] = [1, 2, 3];nums.push(4);console.log(nums.length); // 4// Go — slice (dynamic)nums := []int{1, 2, 3}nums = append(nums, 4)fmt.Println(len(nums)) // 4การดำเนินการกับ Slice
หัวข้อที่มีชื่อว่า “การดำเนินการกับ Slice”const letters = ["a", "b", "c", "d"];
// slice (non-mutating)letters.slice(1, 3) // ["b", "c"]
// lengthletters.length // 4letters := []string{"a", "b", "c", "d"}
// slice expressionletters[1:3] // ["b", "c"]
// lengthlen(letters) // 4maps ของ Go เหมือนกับ Record<K,V> หรือ Map<K,V> ของ TypeScript คีย์สามารถเป็น type ใดก็ได้ที่เปรียบเทียบกันได้ (comparable)
// TypeScriptconst scores: Record<string, number> = { alice: 95, bob: 87,};scores["carol"] = 91;delete scores["bob"];console.log(scores["alice"]);// Goscores := map[string]int{ "alice": 95, "bob": 87,}scores["carol"] = 91delete(scores, "bob")fmt.Println(scores["alice"])ลองเล่นดู
หัวข้อที่มีชื่อว่า “ลองเล่นดู”package main
import ( "fmt" "sort")
func main() { // Slice fruits := []string{"banana", "apple", "cherry"} fruits = append(fruits, "date") sort.Strings(fruits) fmt.Println("Fruits:", fruits)
// Map count := map[string]int{} words := []string{"go", "is", "fun", "go", "is", "great", "go"} for _, w := range words { count[w]++ } fmt.Println("Word counts:", count)}Compiling on go.dev (Go 1.27)… offline? an in-browser runtime (~8 MB, Go 1.26) is used instead
Iterator — คำตอบของ Go สำหรับ generator และ for…of (Go 1.23+)
หัวข้อที่มีชื่อว่า “Iterator — คำตอบของ Go สำหรับ generator และ for…of (Go 1.23+)”ตั้งแต่ Go 1.23 loop for range วนบน function ที่มี type iter.Seq[T] (หรือ iter.Seq2[K, V]) ได้ นี่คือ generator ฉบับ Go: ค่าถูกผลิตแบบ lazy ทีละตัวผ่าน yield โดย loop body เป็นผู้บริโภค package slices และ maps มี helper แบบ iterator มาให้ (slices.Values, maps.Keys, slices.Collect, slices.Sorted)
// TypeScript: generator + for…offunction* evens(limit: number) { for (let n = 0; n <= limit; n += 2) yield n;}for (const n of evens(6)) console.log(n); // 0 2 4 6
const keys = [...new Map([["a", 1], ["b", 2]]).keys()];// Go 1.23+: a func(yield func(T) bool) is an iteratorfunc evens(limit int) iter.Seq[int] { return func(yield func(int) bool) { for n := 0; n <= limit; n += 2 { if !yield(n) { return } // consumer broke out of the loop } }}for n := range evens(6) { fmt.Println(n) } // 0 2 4 6
// stdlib helpers return iterators; Collect/Sorted turn them back into sliceskeys := slices.Sorted(maps.Keys(map[string]int{"a": 1, "b": 2})) // [a b]การที่ callback yield คืน false คือวิธีที่ break ส่งสัญญาณกลับไปหาผู้ผลิต — ไม่มี generator object ให้เรียก .return() ต่างจาก generator ของ JS ตรงที่ iterator ของ Go เป็น function ธรรมดา จึง inline ได้ดีและกรณีทั่วไปไม่ต้อง allocate อะไรเลย และตั้งแต่ Go 1.22 ก็เขียน for i := range 10 วนบน int ได้ด้วย