DEV Community

jame in progress
jame in progress

Posted on

Golang เรื่องที่อาจผิดพลาดกับ Array, Slice และ Map

Array Slice Map เวลาสร้างขึ้นมาจะถือว่าเป็น Reference type โดยอัตโนมัติ ผมจะแสดงให้เห็นผ่านตัวอย่างต่างๆ พร้อมวิธีรับมือครับ

Array

arr := [3]int{0,1,2}
Enter fullscreen mode Exit fullscreen mode

Slice

sli := []int{0,1,2}
Enter fullscreen mode Exit fullscreen mode

Map

m := map[string]bool{
    "1": true,
    "2": true,
    "3": true,
}
Enter fullscreen mode Exit fullscreen mode

โดย Array Slice Map เวลาสร้างขึ้นมาจะถือว่าเป็น Referecne type โดยอัตโนมัติ ผมจะแสดงให้เห็นผ่านตัวอย่างต่างๆ พร้อมวิธีรับมือครับ

เรามาเริ่มต้นกับตัวอย่างด้วย slice, array กัน

before := []string{
    "apple",
    "banana",
    "cherry",
}
fmt.Println("Before: ", before)
/* Before:  [apple banana cherry] */
after := before
before[0] = "__imposter__"

fmt.Println("After: ", after)
/* After:  [__imposter__ banana cherry] */
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์เมื่อรันโปรแกรม

Before:  [apple banana cherry]
After:  [__imposter__ banana cherry]
Enter fullscreen mode Exit fullscreen mode

เราจะเห็นได้ว่าแม้ว่าเราจะกำหนดค่าตัวแปร before มาเป็น after แล้วก็ตาม
แต่เมื่อเปลี่ยนค่าผ่านตัวแปร before[0] เป็น __imposter__
ค่าของตัวแปร after ได้ถูกเปลี่ยนตามไปด้วย

before[0] = "__imposter__"
fmt.Println("After: ", after)
/* After:  [__imposter__ banana cherry] */
Enter fullscreen mode Exit fullscreen mode

เรามาทดลองกันอีกสักหน่อย

package main

import "fmt"

func main() {
    before := []string{
        "apple",
        "banana",
        "cherry",
    }
    fmt.Println("before: ", before)
    /*before:  [apple banana cherry]*/
    after := before
    UpdateSlice(before)

    fmt.Println("after: ", after)
    /*after:  [__imposter__ banana cherry]*/
}

func UpdateSlice(v []string) {
    if len(v) <= 0 {
        return
    }
    v[0] = "__imposter__"
}
Enter fullscreen mode Exit fullscreen mode

สังเกตุว่า UpdateSlice(before) เมื่อเราส่งค่า before ไปเปลี่ยนค่าผ่าน function UpdateSlice
แต่ผลลัพธ์ที่ได้ของตัวแปร after มีการเปลี่ยนไป ถึงแม้ว่าจะไม่ส่งแบบ pointer ก็ตาม

วิธีรับมือ

เราสามารถรับมือได้ด้วน build-in function ที่ชื่อว่า copy ครับ

copy(destination, source)
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง

before := []string{
    "apple",
    "banana",
    "cherry",
}
fmt.Println("Before: ", before)
/* Before:  [apple banana cherry] */
after := make([]string, len(before))
copy(after, before)

before[0] = "__imposter__"

fmt.Println("After: ", after)
/* After:  [apple banana cherry] */
Enter fullscreen mode Exit fullscreen mode

แค่นี้ค่าของตัวแปร after ก็จะถูกเเยกจากกับตัวแปร before เดิมเรียบร้อยครับ 🎉🎉🎉

เรามาดูตัวอย่าง Map กันบ้าง

before := map[string]bool{
    "apple":  true,
    "banana": true,
    "cherry": true,
}
after := before
before["apple"] = false

for k, v := range after {
    fmt.Printf("%v:\t %v\n", k, v)
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้ ซึ่งเราจะเจอเหตุการณ์ที่คล้ายกัน คือ key apple ของ ตัวแปร after ถูกเปลี่ยนเป็น false

apple:   false
banana:  true
cherry:  true
Enter fullscreen mode Exit fullscreen mode

วิธีรับมือ

เราสามารถใช้ function ที่ชื่อว่า maps.Clone(source)

maps.Clone(source)
Enter fullscreen mode Exit fullscreen mode
before := map[string]bool{
    "apple":  true,
    "banana": true,
    "cherry": true,
}
after := maps.Clone(before)
before["apple"] = false

for k, v := range after {
    fmt.Printf("%v:\t %v\n", k, v)
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้ แค่นี้เราก็รับมือกับปัญหานี่ได้เล้วครับ 🎉🎉🎉

apple:   true
banana:  true
cherry:  true
Enter fullscreen mode Exit fullscreen mode

Top comments (0)