登录
首页 >  Golang >  Go问答

在 Go 中获取切片元素地址是否会创建副本?

来源:stackoverflow

时间:2024-02-17 15:33:23 353浏览 收藏

亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《在 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 编译器是否将切片元素临时复制到循环范围内,或者是否将切片元素的地址放入-地点

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

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


正确答案


&sl[i] 不会复制切片元素,它只是计算 ith 元素的地址。

切片元素充当变量,&x 的计算结果为 x 变量的 address。想一想:既然&sl[i]ith元素的地址,该地址不需要也不使用结构体值,为什么要复制呢?

如果您的切片太大,以至于您担心(隐式)副本对性能的影响,那么您确实应该首先考虑在切片中存储指针,这样您就可以使循环和访问元素变得更加方便更简单,无需担心副本:

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] 表达式的计算)。

今天关于《在 Go 中获取切片元素地址是否会创建副本?》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>