为了账号安全,请及时绑定邮箱和手机立即绑定

获取切片元素的地址是否意味着 Go 中元素的副本?

获取切片元素的地址是否意味着 Go 中元素的副本?

Go
绝地无双 2023-03-15 15:00:03
假设一个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])。


查看完整回答
反对 回复 2023-03-15
  • 1 回答
  • 0 关注
  • 146 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号