从范围生成的值具有相同的指针值

时间:2018-08-13 20:06:07

标签: go

对于这两个结构

type A struct {
    Number *int
}

type B struct {
    Number int
}

如果我想在B的切片上循环并将B.Number的值分配给新的A.Number

func main() {
    aSlice := []A{}
    bSlice := []B{B{1}, B{2}, B{3}}
    for _, v := range bSlice {
        a := A{}
        a.Number = &v.Number
        aSlice = append(aSlice, a)
    }
}  

我会发现所有aSlice a.Number都是相同的值和相同的指针。

for _, v := range aSlice {
        fmt.Printf("aSlice Value %v Pointer %v\n", *v.Number,v.Number)
    }

将打印
aSlice值3指针0x10414020
aSlice值3指针0x10414020
aSlice值3指针0x10414020

那么range是否只更新for循环中的 _,v 的值,并且不更改指针?

完整代码:https://play.golang.org/p/2wopH9HOjwj

2 个答案:

答案 0 :(得分:4)

发生这种情况是因为变量v是在循环开始时创建的,并且没有更改。因此,aSlice中的每个元素都有一个指向相同变量的指针。您应该这样写:

for _, v := range bSlice {
    a := A{}
    v := v
    a.Number = &v.Number
    aSlice = append(aSlice, a)
}

您在每次迭代时都使用自己的指针创建新变量。

答案 1 :(得分:1)

正如@Adrian所说,这与记忆无关。 A结构实际上包含一个指向整数值的指针。

type A struct {
    Number *int
}

因此,当您将bSlice的值分配给A结构时,然后将A的{​​{1}}结构附加到aSlice结构类型的A中。它会像在Golang中那样附加值。

但是您正在更改A结构所指向的地址处的值。并在每次迭代中以一个新值开头,该值会更改该地址处的值。

a.Number = &v.Number // here a.Number points to the same address 

因此,aSlice包含最后更新的整数值3。由于aSlice是A结构的一个切片,因此它包含A结构内部的值为3

但是,如果您没有在int结构内创建指向A的指针

type A struct {
    Number int
}

您将获得预期的输出,现在使用的地址与此不同。

package main

import (
    "fmt"
)

type A struct {
    Number int
}

type B struct {
    Number int
}

func main() {
    aSlice := []A{}
    bSlice := []B{B{1}, B{2}, B{3}}
    fmt.Println("----Assignment Loop----")
    for _, v := range bSlice {
        a := A{}
        a.Number = v.Number
        aSlice = append(aSlice, a)
        fmt.Printf("bSlice Value %v Pointer %v\n", v.Number, &v.Number)
        fmt.Printf("  a    Value %v Pointer %v\n", a.Number, &a.Number)
    }
    fmt.Println("\n----After Assignment----")
    fmt.Printf("%+v\n", aSlice)
    for i, _ := range aSlice {
        fmt.Println(aSlice[i].Number)
    }
}

Go playground上的工作代码

在Golang规范中,它为复合文字定义为:

  

获取复合文字的地址会生成指向   用文字值初始化的唯一变量。

type Point3D struct { x, y, z float64 }
var pointer *Point3D = &Point3D{y: 1000}