为什么Go语言中使用for range遍历slice并存入map时,所有值会变成最后一个元素?

为什么Go语言中使用for range遍历slice并存入map时,所有值会变成最后一个元素?

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的值都指向最后一个元素“博客”:

立即学习go语言免费学习笔记(深入)”;

pprof.cn => 博客 测试 => 博客 博客 => 博客

问题根源: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数据结构的细节,并避免此类陷阱。

以上就是

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享