为什么Go语言中使用for range遍历slice并存入map时,所有值会变成最后一个元素?
go语言
ai
作用域
为什么
Go语言Map迭代陷阱:为何所有值都指向最后一个元素?
Go语言中的for...range
循环与map
数据结构结合使用时,容易出现一个常见的陷阱:当遍历切片并将元素添加到map
中时,所有map
的值最终都指向最后一个元素。本文将通过代码示例分析其原因,并提供解决方案。
让我们来看一段代码:
type Student struct { Name string Age int } func main() { m := make(map[string]*Student) students := []Student{ {Name: "pprof.cn", Age: 18}, {Name: "测试", Age: 23}, {Name: "博客", Age: 28}, } for _, stu := range students { m[stu.Name] = &stu // 问题出在这里 } for k, v := range m { fmt.Println(k, "=>", v.Name) } }
登录后复制
这段代码的预期结果是将students
切片中的每个Student
结构体存储到map
中。然而,运行结果却显示所有map
的值都指向最后一个元素“博客”:
<code>pprof.cn => 博客 测试 => 博客 博客 => 博客</code>
登录后复制
问题根源:for...range
循环的变量作用域
问题在于for...range
循环中,stu
变量并非每次迭代都创建一个新的变量。它指向的是students
切片中同一个内存地址。每次迭代,stu
的值都会被更新,但其内存地址保持不变。因此,当循环结束后,map
中的所有指针都指向stu
的最终值(最后一个元素)。
解决方案:创建新的变量副本
为了解决这个问题,我们需要在每次迭代中创建一个stu
变量的副本,确保map
中存储的是不同的内存地址。修改后的代码如下:
for _, stu := range students { newStu := stu // 创建副本 m[newStu.Name] = &newStu }
登录后复制
或者,更简洁的方法是直接创建新的Student
结构体:
for _, stu := range students { m[stu.Name] = &Student{Name: stu.Name, Age: stu.Age} // 创建新的Student实例 }
登录后复制
通过以上修改,map
中的每个值将指向不同的内存地址,从而避免了所有值都指向最后一个元素的情况。 运行修改后的代码将得到预期的结果。
希望这个解释能够帮助您理解Go语言中for...range
循环和map
数据结构的细节,并避免此类陷阱。
以上是为什么Go语言中使用for range遍历slice并存入map时,所有值会变成最后一个元素?的详细内容。更多信息请关注PHP中文网其他相关文章!
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
