一尘不染

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

go

我在正在研究的项目中遇到问题。我找到了解决方法,但是我不确定为什么我的解决方案有效。我希望对Go指针的工作方式有更多经验的人能对我有所帮助。

我有一个Model接口和一个实现该接口的Region结构。Model接口是在Region结构的指针上实现的。我也有一个Regions集合,它是Region对象的一部分。我有一种方法可以将Regions对象转换为[]
Model:

// Regions is the collection of the Region model
type Regions []Region

// Returns the model collection as a list of models
func (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 models
func (coll *Regions) ToModelList() []Model {
    output := make([]Model, len(*coll))
    for idx, _ := range *coll {
        i := (*coll)[idx]
        output[idx] = &i
    }
    return output
}

这样可以在输出切片中提供两个不同地址的预期输出。

老实说,这似乎是一个范围函数在两次运行之间重用相同内存地址的错误,但我始终认为在这种情况下我会丢失某些内容。

我希望我为您解释得足够好。我很惊讶原来的解决方案没有用。

谢谢!


阅读 282

收藏
2020-07-02

共1个答案

一尘不染

在您的第一个(无效)示例中,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])
    }
}
2020-07-02