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

Golang重用内存地址从切片复制?

Golang重用内存地址从切片复制?

Go
白衣非少年 2021-10-04 09:32:41
我在我正在进行的项目中遇到了一个问题。我找到了解决方法,但我不确定为什么我的解决方案有效。我希望对 Go 指针如何工作有更多经验的人可以帮助我。我有一个 Model 接口和一个实现该接口的 Region 结构。Model 接口是在 Region 结构体的指针上实现的。我还有一个 Regions 集合,它是 Region 对象的一部分。我有一个可以将 Regions 对象转换为 []Model 的方法:// Regions is the collection of the Region modeltype Regions []Region// Returns the model collection as a list of modelsfunc (coll *Regions) ToModelList() []Model {    output := make([]Model, len(*coll))    for idx, item := range *coll {        output[idx] = &item    }    return output}当我运行这段代码时,我最终得到了多次输出的指向 Region 的第一个指针。因此,如果 Regions 集合有两个不同的项目,我将获得重复两次的相同地址。当我在切片中设置变量之前打印变量时,它们具有正确的数据。我有点搞砸了,认为 Go 可能会在循环之间重用内存地址。这个解决方案目前在我的测试中对我有用:// Returns the model collection as a list of modelsfunc (coll *Regions) ToModelList() []Model {    output := make([]Model, len(*coll))    for idx, _ := range *coll {        i := (*coll)[idx]        output[idx] = &i    }    return output}这给出了输出切片中两个不同地址的预期输出。老实说,这似乎是 range 函数在两次运行之间重用相同内存地址的错误,但我总是认为在这种情况下我会遗漏一些东西。我希望我已经为你解释得足够好。我很惊讶原来的解决方案不起作用。
查看完整描述

2 回答

?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

在您的第一个(非工作)示例中item是循环变量。它的地址没有变化,只有它的价值。这就是为什么您在输出idx时间内获得相同地址的原因。


运行此代码以查看正在运行的机制;


func main() {


    coll := []int{5, 10, 15}


    for i, v := range coll {

       fmt.Printf("This one is always the same; %v\n", &v)

       fmt.Println("This one is 4 bytes larger each iteration; %v\n", &coll[i])

    }

}


查看完整回答
反对 回复 2021-10-04
?
侃侃尔雅

TA贡献1801条经验 获得超16个赞

item整个循环只有一个变量,在循环的每次迭代中都会为其分配相应的值。您不会item在每次迭代中获得新变量。所以你只是重复取同一个变量的地址,这当然是相同的。


另一方面,如果你在循环内部声明了一个局部变量,它在每次迭代中都会是一个新变量,并且地址会有所不同:


for idx, item := range *coll {

    temp := item

    output[idx] = &temp

}


查看完整回答
反对 回复 2021-10-04
  • 2 回答
  • 0 关注
  • 237 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信