[Go] Golang 的 slice 進階know how


之前聽別人分享使用slice 遇到有些坑,但未說明來由。

最近在閱讀Golang 新手可能会踩的 50 个坑(英文原文)

也看到關於slice說明的一些現象,為什麼有些值會無故消失,或者無故被更改,於是好奇花了些時間研究了一下。

下列說明配合source code,這邊就不重複貼了。
my source code on github



先說結論,slice的使用方式是pointer。

slice、map、channel 三者在Golang使用上是操作方式是pointer,不熟悉的話建議先把內容copy起來再操作比較保險。

請參考GO FAQ
Why are maps, slices, and channels references while arrays are values?

我自己在寫FAQ的心得文章有印象。

當下是以為在傳遞function的參數,和接受參數的部分對於 maps, slices, and channels 有這樣的說明,不過現在看來這個也是在講平常assign的使用上。




實驗分為test1() test2() test3()。

test1() 和test2()

把某個slice assign到另外一新的變數,表面上看似有了兩個slice,不過是多了一個新的變數名稱,其實指到相同的slice內容而已。

如果改了其中的內容,兩個slice都會影響到,因為他們是指向同樣的地方。

但若(舊的slice + 新的value) ----> 就會自動產生出新的slice,於是跟舊的slice沒有關係了,各改各的不會受影響。



test3()
將記憶體位置印出來,事實上實驗起來,可以發現每個slice裡面的index皆占了一個記憶體空間,假設有兩個slice,裡面的元素可以指向同樣的地方,也可以分別指到不同的地方


    x := append(s, 11) // 只有擴到x,但s還是舊的
    fmt.Println("cap(s) =", cap(s), "ptr(s) =", &s[0], "ptr(x) =", &x[0])
    fmt.Println("cap(s) =", cap(s), "ptr(s) =", &s[1], "ptr(x) =", &x[1])
    fmt.Println("cap(s) =", cap(s), "ptr(s) =", &s[2], "ptr(x) =", &x[2])

    b := &s[2]
    *b = 100
    fmt.Println(s)
    fmt.Println(x)


如果這個時候,要印&s[3]是會發生錯誤的,但如果要印出&x[3]沒有問題,裡面放的就是後來加上去的11。

所以s[3]和x[3]可以指到不同的地方,不會因為&x[3]指向了某處,而變向讓s[3]也跟著他一起指向了某處。




後記:
對目前的我要肉眼compile寫下的slice會不會有問題,可能有些困難,尋求的建議是使用之前使用copy(),將slice複製一份後,即可安心操作。


查找資料實,在網路上有找到某位大大精闢的文章講解slice和map,真的十分精彩。
Go语言实战笔记(五)| Go 切片
Go语言实战笔记(六)| Go Map

Created Date : 2018/08/13

Last Updated Date : 2018/08/13


留言

這個網誌中的熱門文章

[Go] 型態轉換 type convert

[Go] Golang用法 package import 前面的底線

[Go] 指標 pointer with golang