前言
在网上发现一道golang 中的 for range 和 & 取地址结合的题目,感觉很有趣,先来看看演示代码。
演示代码
package main
import "fmt"
type student struct {
name string
age int
}
func main() {
m := make(map[string]*student)
stus := []student{
{name: "小王子", age: 18},
{name: "娜扎", age: 23},
{name: "大王八", age: 9000},
}
for _, stu := range stus {
m[stu.name] = &stu
}
for k, v := range m {
fmt.Println(k, "=>", v.name)
}
}
输出结果:
小王子 => 大王八
娜扎 => 大王八
大王八 => 大王八
是不是很惊愕,结果为什么不是预期的,map的值都是一个呢?
原因分析
for range 每次产生的 key 和 value 其实是对应的 stus 里面值的拷贝,不是对应的 stus 里面的值的引用,所以出现了这种问题。
stu 是 stus 在for循环中申请的一个局部变量,每次循环都会拷贝 stus 中对应的值 stu。迭代遍历之后,stu 每次会被重新赋值,而在 m 这个 map 中记录的 value 只不过是 stu 的内存地址。
我可以打印一下 &stu 的内存地址:
... ...
for _, stu := range stus {
fmt.Printf("%p\n",&stu)
m[stu.name] = &stu
}
... ...
输出内存地址如下:
0xc00000c030
0xc00000c030
0xc00000c030
小王子 => 大王八
娜扎 => 大王八
大王八 => 大王八
会发现所有的内存地址都是一样的
解决方案
重新申请一个变量,即可解决
... ...
for _, stu := range stus {
s := stu
m[stu.name] = &s
}
... ...
输出内存地址如下:
大王八 => 大王八
小王子 => 小王子
娜扎 => 娜扎
注意:
修改后,这里输出的结果每次运行结果都不一样,因为 map 数据是无序的。
本文探讨了Golang中forrange与地址符&结合的编程问题,展示了为何map值并非预期,深入剖析了拷贝行为并给出了解决方案。通过实例和内存地址分析,揭示了如何正确使用forrange避免此类意外结果。
1076

被折叠的 条评论
为什么被折叠?



