英文:
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 length0and capacity (at least)3. -
As soon as the capacity is enough to append the values - the underlying array is reused
-
You write
bandcinto the indexes0and1correspondingly 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论