package main
import "fmt"
func main() {
x := make([]int,0,10)
x = append(x, 1,2,3)
y := append(x,4)
z := append(x,5)
fmt.Println(x)
fmt.Println(y)
fmt.Println(z)
}
为什么 y
输出的也是 [1 2 3 5]
呢?append()
不是拷贝 x
的值么,那怎么 z
把 y
也覆盖了
https://pkg.go.dev/builtin#ap...
简而言之,如果 append 的 slice 有足够容量,就不重新分配内存。只有容量不足的时候才会重新分配。
参考这篇 go 团队的博客 把 slices 说的很详细了。
重新审题。
你的问题是为什么
append(x,5)
之后y
也跟着变了,要理解这一点必须理解 slice 类型是怎么回事。上面链接里 Go 官方团队是这么说的:
slice 是一个包含指针的结构值,保存了指针和长度。 slice 是 值 而不是 引用 理解这一点很重要。
再看你的代码。
我们一句一句解读。
把
x
看作一个结构值struct { underlying: *[cap]int, len: 0 }
,已知cap
足够,不重新分配底层数组,这一句append
调用做的事情就是:然后看这一句。
经过第一个
append
,现在的x
是struct{ underlying: [cap]int, len: 3}
,cap
依然足够。所以append
的实际行为如下。最后是
z = append(x, 5)
因为
x
/y
/z
共享底层数组,append
在y
和z
处调用时,根据x
的长度,修改的都是第4个元素,造成执行append(x, 5)
之后y
的第4个元素也变成了5。而
y = append(x, 4)
没有修改 x 的原因是,修改了但没有表现出来。因为x.len
指明x
的长度只有 3 ,虽然底层数组第 4 个元素已经被修改成了 4 ,但打印 x 的时候是不会打印出 4 的。同理,
z = append(x, 5)
修改的底层数组是和x
共享的,在执行了append(x, 5)
之后其实x
的底层数组第4个元素已经变成了5,只是x
里保存的长度还是3,所以你没法看到它的第4个元素。但y
和z
共享底层数组,而且y
的长度是4,所以你能看到y
的第4个元素变成了5。