場景
package main
import "fmt"
type cities []string
func main() {
Nepal := cities{"Kathmandu", "Pokhara", "Lumbini"}
Nepal.add()
Nepal.print()
}
func (c cities) print() {
for i, city := range c {
fmt.Println(i, city)
}
}
func (c cities) add() {
c = append(c, "hello")
}
執行輸出如下:
0 Kathmandu
1 Pokhara
2 Lumbini
結果沒有 3 hello
原因
slice
跟 array
很類似,但是它更靈活,可以自動擴容.
由原始碼可以看到它的本質:
// runtime/slice.go
type slice struct {
array unsafe.Pointer // 元素指標
len int // 長度
cap int // 容量
}
slice
有三個屬性,分別是指向底層陣列的指標,切片可用的元素個數,底層陣列的元素個數.
底層的陣列可能被多個
slice
指向,所以修改其中一個slice
的時候,會因此影響到其他的slice
.
上面的程式碼 c = append(c, "hello")
之後,遍歷 c
卻沒有 hello
,這主要涉及到 slice
的擴容問題.
在新增元素的時候,如果 slice
的容量不夠的時候,是會先讀取原有元素,然後 cap 擴大一倍,再重新複製到新的陣列中去,slice
的陣列指標也更新為新的陣列指標.
把上面程式碼 c
的指標地址列印下,就清晰很多了.
package main
import "fmt"
type cities []string
func main() {
Nepal := cities{"Kathmandu", "Pokhara", "Lumbini"}
Nepal.add()
Nepal.print()
}
func (c cities) print() {
fmt.Printf("print(): %p \n", c)
for i, city := range c {
fmt.Println(i, city)
}
}
func (c cities) add() {
fmt.Printf("add() append before: %p \n", c)
c = append(c, "hello")
fmt.Printf("add() append after: %p \n", c)
}
輸出如下:
add() append before: 0xc000070150 # append 前後地址不一樣
add() append after: 0xc00007c120
print(): 0xc000070150
0 Kathmandu
1 Pokhara
2 Lumbini
解決
在 add()
方法的時候,使用指標賦值,直接修改原來的 slice
.
func (c *cities) add() {
*c = append(*c, "hello")
}
輸出如下:
0 Kathmandu
1 Pokhara
2 Lumbini
3 hello
參考
how-to-append-to-a-slice-pointer-receiver
深度解密Go語言之Slice
如果覺得不錯,可以給我一個 STAR
本作品採用《CC 協議》,轉載必須註明作者和本文連結