[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
留言
張貼留言