為什么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 分享