如何解决在golang中修改地图值-有无指针-意外行为
我是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答案(np.where
),解决方案是将元素“重新分配”回地图。很好,但是还可以。
另一个选择是创建指向该结构的指针的映射,但是最终导致一个相关的悖论。考虑以下更新程序:
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)
}
}
我希望输出为:
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",v := range myData {
fmt.Println(v.Value)
}
}
显然,必须有一种更好的方法。所以我问你-StackOverflow社区的明智人-到底发生了什么?
解决方法
您要声明一个值,并存储两个指向相同值的指针。
以下内容声明foo
并将字面量{ID:"one",Value:"oneval"}
分配给is:
foo := data{ID: "one",Value: "oneval"}
这会在地图中存储指向foo
的指针。
myData["one"] = &foo
这会用新值foo
覆盖{ID:"two",Value:"twoval"}
的内容:
foo = data{ID: "two",Value: "twoval"}
这时,myData["one"]
指向包含foo
的{{1}}。
您需要存储指向两个不同内存位置的指针:
{ID:"two",Value:"twoval"}
或更简单:
foo := data{ID: "one",Value: "oneval"}
myData["one"] = &foo
foo2 := data{ID: "two",Value: "twoval"}
myData["two"] = &foo2
,
通过分配变量,您不会更改其在内存中的地址。您只需更改其值即可。
foo := data{ID: "one",Value: "oneval"}
myData["one"] = &foo
foo = data{ID: "two",Value: "twoval"}
myData["two"] = &foo
此处您要更改变量foo
的值。在整个程序中,它的地址保持不变。因此,当您将foo
的地址分配给myData["one"]
并随后分配给myData["two"]
时,实际上是将相同的值分配给了两者。
fmt.Println(myData["one"] == myData["two"]) //true
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。