各位前輩好:
我看到一個例子,程式碼如下:
func SliceRise(s []int) {
s = append(s, 0)
for i := range s {
s[i]++
}
fmt.Println(s)
}
func main() {
//hello.goSliceExtend()
slice1 := []int{1,2}
slice2:= slice1
slice2=append(slice2,3)
slice2[0]=0
slice2[1]=1
slice2[2]=2
SliceRise(slice1)
SliceRise(slice2)
fmt.Println(slice1)
fmt.Println(slice2)
}
執行結果是:
[2 3 1]
[1 2 3 1]
[1 2]
[1 2 3]
想請問為什麼 slice1=[1,2],不是[2,3,1]
slice2=[1,2,3],不是[1,2,3,1]? 謝謝.
Hi fredfu5431 and froce,
不好意思,我忽略了 Slice
的特性,在 Go 中, Slice
有以下屬性:
在你提供的範例中, slice1
與 slice2
的 cap
一開始都是 2
(他們參照了同一塊記憶體空間)。
不過,你在這邊做了一個關鍵的動作:
slice2=append(slice2,3)
因為 slice2
壓根沒有這麼多容量,所以當你做了 append()
時, Go 就為 slice2
分配了更大的空間,並把原本的值複製過去,這時 slice2
的屬性:
再來,你呼叫了兩次 SliceRise()
,並且 SliceRise
中都用了一次 append
,不過,因為 slice1
與 slice2
的 cap 已經不同了,所以會有不同的結果:
slice1
來說:slice1
沒有這麼多容量,所以當你做了 append()
時, Go 就為 s
分配了更大的空間,所以你在 SliceRise(slice1)
中操作的是全新的記憶體空間。slice2
來說:append()
讓 cap 更大了,所以你再一次呼叫 append()
時, slice2
還是裝的下(也就意味著這裡的 s
跟 slice2
參照的記憶體相同),操作的自然是同一塊記憶體了。不會,我也學習了 XD
其實你應該留下原本的回答的,因為我沒仔細看你的code...
append的行為似乎不太對喔。
https://www.gushiciku.cn/pl/2dtT/zh-tw
這例子應該是在
slice2=append(slice2,3)
的時候,產生新的slice2,cap為4
然後
SliceRise(slice1)
的時候,產生新的slice1,cap也為4
最後
SliceRise(slice2)
的時候,因為元素個素小於等於4,沒產生新的slice2
用cap(slice)可以看
有問題可以把記憶體位置print出來看
不過我不知道是不是append遇到如果還有連續的記憶體空間的話,就還是用同一個記憶體位址
用下面的playround跑看起來是,但cap是依照上面說的規則變的。
另外其實一開始
slice2:= slice1
的時候,slice2已經和slice1脫鉤了,slice2是slice1的clone
其實我跟你表達的意思差不多,我不覺得有哪個部分不對⋯
然後我本來的答案跟你下面提供的程式碼一樣,都是提到傳址的概念。會特別標註您只是因為我們一開始好像都誤會了樓主的意思,所以提供一下更新後的回答給各位。
golang傳參是複製一份值傳進去,所以你的SliceRise裡面的s都不是本來的slice
你想要的需要用指標。
package main
import (
"fmt"
)
func SliceRise(s *[]int) {
*s = append(*s, 0)
for i := range *s {
(*s)[i]++
}
fmt.Println(*s)
}
func main() {
//hello.goSliceExtend()
slice1 := []int{1,2}
slice2:= slice1
slice2=append(slice2,3)
slice2[0]=0
slice2[1]=1
slice2[2]=2
SliceRise(&slice1)
SliceRise(&slice2)
fmt.Println(slice1)
fmt.Println(slice2)
}