获取切片元素的地址是否意味着 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

    }

}

关键是<-- HERE,Golang 编译器是将slice 元素的临时副本复制到循环的范围内,还是就地获取 slice 元素的地址?


这个想法是为了避免复制整个切片元素。


一个工作示例:https://go.dev/play/p/jHOC2DauyrQ ?v=goprev


绝地无双
浏览 147回答 1
1回答

森栏

&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])。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go