Golang 会正确优化范围循环并避免复制每个对象吗?

Will Golang properly optimize a for range loop and avoid copying each object?

提问人:Alexis Wilke 提问时间:7/13/2023 更新时间:7/13/2023 访问量:118

问:

在我正在编写的一些 Go 代码中,我经常看到这样的循环:

var slice []SomeType
...fill slice...
for idx, obj := range slice {
    obj.SetSomeValue(123)
    slice[idx] = obj
}

obj将是中找到的对象的副本(尽管不是指针,因为它使用浅副本)。slice

我想知道的是:现有的 Go 编译器是否能够通过将 直接应用于 at 的对象来优化循环,还是像上面的代码所暗示的那样制作两个副本?SetSomeValue()slice[idx]

我的简单解决方案是改用指针,因此切片变为:

var slice []*SomeType

则 loop 变量是指向对象的指针,因此它在这里只复制一个指针,并且调用直接应用于 中的对象。objSetSomeValue()slice

另一种解决方案是按如下方式对切片进行调用:

for idx, _ := range slice {
    slice[idx].SetSomeValue(123)
}

但是,在这种情况下,重复和编译时也可能最终重复多次(尽管我仍然认为这比第一种方法更好)。slice[idx].

数组 复制 切片

评论

1赞 Burak Serdar 7/13/2023
如果您担心副本,请使用索引访问。编译器可以优化索引的重复使用。通过直接访问切片来优化对副本的访问会改变语言语义并引入错误,因此编译器无论如何都不应该这样做。还可以通过将切片索引的地址分配给指针变量来使用一次索引访问。
0赞 Alexis Wilke 7/13/2023
@BurakSerdar 没错,for 块中的第一个语句可以是 。我很担心,因为其中一些列表有数百万个项目(大约 10M)。我认为这是一个有用的优化,特别是因为对象(SomeType)不是那么小。obj := &slice[idx]
2赞 Burak Serdar 7/13/2023
然后使用索引访问。你不想复制整个事情。不过,不要指望编译器会优化副本,它会改变这个含义:使用您建议的复制优化,始终为 1。for a, b:=range slice { slice[a].x=1; y:=b.x }y

答: 暂无答案