英文:
How does append() work behind the scenes that's causing this?
问题
我对Go语言还不太熟悉,但我会尽力帮你翻译。以下是你要翻译的内容:
我对Go语言还不太熟悉,但我在追踪我的代码库中的一个错误。在这个过程中,我将问题简化为对append()
的单个调用,但是我无法弄清楚它为什么会表现出这种行为...
func main() {
foo := []string{"a", "b", "c"}
fmt.Printf("before: %v\n", foo)
i := 0
noop(append(foo[:i], foo[i+1:]...)) // -- 调用append,但不对结果进行任何操作
fmt.Printf(" after: %v\n", foo)
}
func noop(a interface{}) {} // -- 避免出现"evaluated but not used"错误
那么,到底发生了什么?
英文:
I'm pretty new to Go and trying to track down a bug in my codebase. In the process I've distilled the problem down to a single call to append()
, but can't figure out why it's behaving the way it is...
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
So, what the heck is really going on here?
答案1
得分: 6
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
英文:
append(foo[:i], foo[i+1:]...)
does the following:
-
It takes the
foo[:i]
slice, which isfoo[:0]
and basically a slice with length0
and capacity (at least)3
. -
As soon as the capacity is enough to append the values - the underlying array is reused
-
You write
b
andc
into the indexes0
and1
correspondingly of the underlying array.
Then you check the foo
variable that uses the underlying array we just modified and that contains the b c c
values.
Compare with the following:
noop(append(foo[:i], "a", "a", "a", "a", "a"))
Here the list of values to append is longer than the current capacity. So the runtime allocates a new underlying array. And you don't mutate the foo
. https://play.golang.org/p/RooYG_p9Z8
答案2
得分: 3
如果s
的容量不足以容纳额外的值,append
会分配一个足够大的新底层数组,该数组可以容纳现有的切片元素和额外的值。否则,append
会重用底层数组。
具体来说,这里的s
是foo[:0]
,它的容量至少为3,因为foo
的长度为3。s
没有元素,而append
想要添加两个元素[b c]
,所以有空间,append
将重用foo[:0]
的底层数组,该数组与foo
的底层数组相同。
因此,它将项目[b c]
放在数组的开头,并返回一个长度为2的新切片。
但是你仍然在看foo
,它是同一个数组的切片,但长度仍为3;第三个元素是未被修改的c
,所以foo
现在是[b c c]
。
英文:
> If the capacity of s
is not large enough to fit the additional values, append
allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append
re-uses the underlying array.
Breaking it down, s
here is foo[:0]
, which has a capacity of at least 3, since the length of foo
is 3. s
has 0 elements, and append wants to add two elements, [b c]
, so there is room, and append
will re-use the underlying array of foo[:0]
which is the same as the underlying array of foo
.
So it places the items [b c]
at the beginning of the array, and returns a new slice of that array with a length of 2.
But you're still looking at foo
, which is a slice of that same array, but still has a length of 3; the third item is the c
which hasn't been touched, so foo
is now [b c c]
.
答案3
得分: 2
我对Go语言也比较新,但我对append
的理解是它将所有后续的参数追加到第一个参数中。
所以基本上你所做的是将foo[1]
和foo[2]
追加到foo[0]
和foo[1]
,而不实际改变foo
的长度。
如果你想保留原始切片,你需要的是这个。
英文:
I'm also relatively new to go, but the way I understand append
is that it appends all the following arguments to the first argument.
So essentially what you are doing is appending foo[1]
and foo[2]
to foo[0]
and foo[1]
without actually changing the length of foo
.
If you want to preserve the original slice what you want is this
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论