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

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

Apr 02, 2025 pm 04:09 PM
go语言 ai 作用域 为什么

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

<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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。