我是golang的新手,所以我试图从其他语言(例如Java/JavaScript)中调整我的思维,并将其应用于golang。在大多数情况下,这是很直接的。然而,当涉及到跨图迭代和修改值时,我就有点束手无策了。

考虑一下下面的示例程序。

package main

import "fmt"

type data struct {
    ID    string
    Value string
}

func main() {

    myData := make(map[string]data)

    foo := data{ID: "one", Value: "oneval"}
    myData["one"] = foo
    foo = data{ID: "two", Value: "twoval"}
    myData["two"] = foo

    for _, v := range myData {
        fmt.Println(v.Value)
        v.Value = "kenny"
    }
    for _, v := range myData {
        fmt.Println(v.Value)
    }
}

在大多数语言中,我希望输出结果是。

oneval
twoval
kenny
kenny

当然,这不是。它是

oneval
twoval
oneval
twoval

感谢这个SO答案(How to update map values in Go),解决方案是将元素 "重新分配 "到地图中。哎哟,不过还好。

另一个选择是创建一个指向该结构的指针映射,但这最终导致了相关的悖论。考虑一下这个更新的程序。

package main

import "fmt"

type data struct {
    ID    string
    Value string
}

func main() {
    // Now it's a map of struct pointers...
    myData := make(map[string]*data)

    foo := data{ID: "one", Value: "oneval"}
    myData["one"] = &foo
    foo = data{ID: "two", Value: "twoval"}
    myData["two"] = &foo

    for _, v := range myData {
        fmt.Println(v.Value)
        v.Value = "kenny"
    }
    for _, v := range myData {
        fmt.Println(v.Value)
    }
}

我本来以为输出结果会是。

oneval
twoval
kenny
kenny

其实是这样的。

twoval
kenny
kenny
kenny
foo

因此,要想让它如愿以偿地工作,唯一的办法就是这样做。

package main

import "fmt"

type data struct {
    ID    string
    Value string
}

func main() {
    // Now it's a map of struct pointers...
    myData := make(map[string]*data)

    {
        foo := data{ID: "one", Value: "oneval"}
        myData["one"] = &foo
    }
    // Really, anything to make 'foo' go out of scope
    foo := data{ID: "two", Value: "twoval"}
    myData["two"] = &foo

    for _, v := range myData {
        fmt.Println(v.Value)
        v.Value = "kenny"
    }
    for _, v := range myData {
        fmt.Println(v.Value)
    }
}

很明显,一定有更好的方法。所以我问你们--StackOverflow社区的智者们--到底发生了什么?