我是Go的新手,试图追踪我的代码库中的错误。在这个过程中,我把问题简化为一次调用append()
,但无法弄清楚为什么它的行为方式......
func main() {
foo := []string{"a", "b", "c"}
fmt.Printf("before: %v\n", foo)
i := 0
noop(append(foo[:i], foo[i+1:]...)) // -- call append, but do nothing with the result
fmt.Printf(" after: %v\n", foo)
}
func noop(a interface{}) {} // -- avoid "evaluated but not used" errors
那么,这到底是怎么回事?
答案 0 :(得分:5)
append(foo[:i], foo[i+1:]...)
执行以下操作:
foo[:i]
切片为foo[:0]
,基本上是一个长度为0
且容量(至少)为3
的切片。
只要容量足以附加值 - 基础数组就会被重用
您将b
和c
写入与基础数组相对应的索引0
和1
。
然后检查使用我们刚修改的基础数组的foo
变量,其中包含b c c
值。
与以下内容比较:
noop(append(foo[:i], "a", "a", "a", "a", "a"))
此处要追加的值列表长于当前容量。所以运行时分配一个新的底层数组。而且你不会改变foo
。 https://play.golang.org/p/RooYG_p9Z8
答案 1 :(得分:3)
如果
s
的容量不足以容纳其他值,append
会分配一个足够大的新基础数组,该数组既适合现有切片元素又符合其他值。否则,append
将重新使用基础数组。
分解,s
此处为foo[:0]
,其容量至少为3,因为foo
的长度为3. s
有0个元素,和append想要添加两个元素[b c]
,因此有空间,append
将重用foo[:0]
的基础数组,它与{{1}的基础数组相同}}
因此它将项foo
放在数组的开头,并返回长度为2的该数组的新切片。
但你还在看[b c]
,它是同一个数组的一部分,但长度仍为3;第三项是未被触及的foo
,因此c
现在为foo
。
答案 2 :(得分:1)
我也比较新,但我理解append
的方式是它将所有以下参数附加到第一个参数。
基本上你正在做的是将foo[1]
和foo[2]
追加到foo[0]
和foo[1]
而不实际更改foo
的长度。
如果您想保留原始切片,您需要的是this