假设一个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 }}关键是<-- HERE,Golang 编译器是将slice 元素的临时副本复制到循环的范围内,还是就地获取 slice 元素的地址?这个想法是为了避免复制整个切片元素。一个工作示例:https://go.dev/play/p/jHOC2DauyrQ ?v=goprev
1 回答

森栏
TA贡献1810条经验 获得超5个赞
&sl[i]
i
不复制 slice 元素,它只是计算第th 个元素的地址。
切片元素充当变量,并&x
计算为变量的地址x
。想一想:既然&sl[i]
是第th个元素的地址i
,这个地址既不需要也不用到struct的值,为什么还要复制呢?
如果你的切片太大以至于你担心(隐式)副本的性能影响,你真的应该首先考虑在切片中存储指针,这样你就可以使你的循环和访问元素变得更加简单,而无需担心副本:
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])。
- 1 回答
- 0 关注
- 146 浏览
添加回答
举报
0/150
提交
取消