英文:
Why does Go slice `append()` not take a reference?
问题
Go语言的切片append()函数可能会分配一个新的后备数组来为新的元素腾出空间。因此,在调用z = append(x, y)之后,如果修改了z的前面的元素,x实际上是未指定的——它可能具有与z相同的后备数组,也可能没有,而z可以使用z[0] = foo来改变其后备数组,这可能会修改x的后备数组。
那么,为什么要让这种丑陋的情况浮出水面呢?与其将append的结果分配给除了第一个参数之外的任何变量都视为程序错误,为什么不让append接受一个*[]T参数,这样就不需要重新赋值,也不会留下未定义的变量。
这并不能解决所有情况,因为a = x; append(&x, y)仍然会使a变为未定义,但是部分改进总比没有好。
英文:
Go Lang's slice append() might allocate a new backing array to make room for the new item. Thus, after a call z = append(x,y), if z's front most elements are modified, x is essentially unspecified -- it might or might not have the same backing array as z, and z could mutate its backing array with z[0] = foo, which thus might or might not modify x's backing array.
So, why let this ugliness surface? Instead making it a program bug to assign the result of append to anything but its first argument, why not have append take a *[]T instead, so no reassignment is needed and no undefined variable is left dangling.
This wouldn't solve every case, because a = x; append(&x,y) would still make a undefined, but a partial improvement seems better than none.
答案1
得分: 3
在你的第一个例子中(z = append(x, y)),并不完全正确说x是未定义的。相反,x仍然指向x的原始内容,而z指向这些内容以及其他内容。正如你提到的,有两种可能性:
cap(x) > len(x),在这种情况下,append只是返回x[:len(x)+1](即,扩展返回的切片的长度以包含一个额外的元素)cap(x) == len(x),在这种情况下,append通过复制x的内容创建另一个数组,然后将y附加为第len(x)个元素。
在这两种情况下,x在很大程度上保持不变,即x的所有元素仍然存在。显然,现在你必须小心,因为你可能有两个引用指向相同的底层数据,但是保留x可能是有用的。
话虽如此,我同意也许让append接受一个指针可能会更简单,而且也许我刚刚描述的这种可能的用例并不常见,不值得采用可能会令人困惑、稍微冗长的语义。
英文:
It's not quite true that in your first example (z = append(x, y)), x is undefined. Instead, x still points to the original contents of x, while z points to those contents and then some. As you mention, there are two possibilities:
cap(x) > len(x), in which caseappendsimply returnsx[:len(x)+1](ie, extends the length of the returned slice to contain one extra element)cap(x) == len(x), in which caseappendcreates another array by copying over the contents ofxand then appendsyas thelen(x)-th element.
In either of these cases, x is left largely unchanged in the sense that all of the elements of x are still there. You obviously have to be careful now that you potentially have two references to the same underlying data, but the point stands that keeping x around can be useful.
That said, I agree that maybe having append take a pointer might be simpler, and maybe this possible use case that I've just described isn't common enough to warrant the potentially confusing, mildly more verbose semantics.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论