提问人:A. Gille 提问时间:11/16/2022 最后编辑:blackgreenA. Gille 更新时间:11/16/2022 访问量:223
获取切片元素的地址是否意味着 Go 中该元素的副本?
Does taking the address of a slice element implies a copy of the element in Go?
问:
假设一个程序有一个 相当沉重的 ,对于它来说,复制被认为是昂贵的:Go 1.18
struct
type MyStruct struct {
P string
// a lot of properties
}
现在让我们定义一个函数,将这些元素的切片作为输入参数,其目标是更新每个切片元素的属性:
func myFunc(sl []MyStruct) {
for i := range sl {
p := &sl[i] // <-- HERE
p.P = "bar"
// other properties mutations
}
}
在标记处,Golang 编译器是在循环的作用域中临时复制 slice 元素,还是在就地获取 slice 元素的地址?<-- HERE
这个想法是避免复制整个切片元素。
答:
2赞
icza
11/16/2022
#1
&sl[i]
不复制 slice 元素,它只是计算到 th 个元素的地址。i
切片元素充当变量,&
x 的计算结果为 x
变量的地址。想一想:既然 &sl[i]
是第 i
个元素的地址,地址不需要也不使用结构值,为什么它会复制呢?
如果你的切片太大了,以至于你担心(隐式)复制对性能的影响,你真的应该首先考虑在切片中存储指针,这样你就可以使你的循环和访问元素变得更加简单,而不必担心复制:
func myFunc(sl []*MyStruct) {
for _, v := range sl {
v.P = "bar"
// other properties mutations
}
}
另请注意,如果您的切片包含非指针,并且您想要更改切片元素的字段,则索引切片并引用该字段也不涉及复制结构元素:
func myFunc(sl []MyStruct) {
for i := range sl {
sl[i].P = "bar"
// other properties mutations
}
}
是的,如果必须修改多个字段,这可能会更详细,并且效率可能更低(但编译器也可以识别和优化多个表达式的计算)。sl[i]
评论
0赞
A. Gille
11/16/2022
感谢您的回答,它证实了我对此类操作的不确定。我知道“指针切片”技巧,但并不总是可以处理指针切片而不是具体类型的元素切片。
评论
sl
myFunc()