为什么切片 a
保持不变? append()
是否生成新切片?
package main
import (
"fmt"
)
var a = make([]int, 7, 8)
func Test(slice []int) {
slice = append(slice, 100)
fmt.Println(slice)
}
func main() {
for i := 0; i < 7; i++ {
a[i] = i
}
Test(a)
fmt.Println(a)
}
输出:
[0 1 2 3 4 5 6 100]
[0 1 2 3 4 5 6]
原文由 Pole_Zhang 发布,翻译遵循 CC BY-SA 4.0 许可协议
在您的示例中,
Test
函数的slice
参数在调用方的范围内接收变量a
_的副本_。由于切片变量包含仅 引用 底层数组的“切片描述符”,因此在您的
Test
函数中,您连续多次修改slice
变量中保存的切片描述符,但是这不会影响调用者及其a
变量。Inside the
Test
function, the firstappend
reallocates the backing array under theslice
variable, copies its original contents over,100
to它,这就是你正在观察的。从Test
退出后,slice
变量超出范围,切片引用的(新)底层数组也超出范围。 ( 杰夫李 是正确的,这不是真正发生的事情,所以更新版本如下;正如他正确指出的那样, 这个答案 是正确的,如果可能有点过于简洁。)在
Test
函数之外,分配了一个长度为7,容量为8的slice,并填充了它的7个元素。在
Test
函数中,第一个append
看到切片的容量仍然比它的长度大一个元素——换句话说,有空间可以再添加一个元素而无需重新分配.所以它“吃掉”剩余的元素并将100
到它,之后它调整切片描述符副本中的长度,使其等于切片的容量。这不会影响调用者范围内的切片描述符。这就是你正在观察的。从
Test
退出后,slice
变量超出范围,切片引用的(新)底层数组也超出范围。如果你想让
Test
表现得像append
, _你必须从它返回新的切片_——就像append
-4bd8- 的调用者需要Test
以相同的方式使用它append
:请仔细阅读 这篇文章,因为它基本上向您展示了如何在解释了切片的内部工作原理之后如何手动实现
append
。然后读 这个。