go語言面試題:深入理解for…range循環(huán)與指針
Go語言的for…range循環(huán)簡潔高效,但使用指針時容易引發(fā)誤解。本文剖析一個常見的面試題,闡明for…range循環(huán)中指針的陷阱及解決方法。
問題描述
考慮一個學(xué)生結(jié)構(gòu)體和學(xué)生切片,目標(biāo)是將學(xué)生信息存儲到map中并打印姓名:
type student struct { name string age int } func main() { m := make(map[string]*student) stus := []student{ {name: "pprof.cn", age: 18}, {name: "測試", age: 23}, {name: "博客", age: 28}, } for _, stu := range stus { m[stu.name] = &stu } for k, v := range m { fmt.Println(k, "=>", v.name) } }
預(yù)期輸出:
pprof.cn => pprof.cn 測試 => 測試 博客 => 博客
實際輸出:
立即學(xué)習(xí)“go語言免費學(xué)習(xí)筆記(深入)”;
pprof.cn => 博客 測試 => 博客 博客 => 博客
問題分析
所有v.name都變成了”博客”,原因在于for…range循環(huán)的迭代變量stu在每次迭代中是同一個變量,只是其值被更新。&stu創(chuàng)建的指針始終指向這個單一變量。循環(huán)結(jié)束后,stu的值為最后一個學(xué)生的信息,因此map中的所有指針都指向了這個最終的stu變量。
Go語言的for…range循環(huán)復(fù)用迭代變量,不會為每次迭代創(chuàng)建新變量。因此,獲取迭代變量的地址將始終得到同一個地址。
解題方法
為了解決這個問題,需要在每次迭代中創(chuàng)建stu的副本:
for _, stu := range stus { stuCopy := stu // 創(chuàng)建副本 m[stu.name] = &stuCopy }
通過創(chuàng)建stuCopy副本,并使用&stuCopy作為map的值,確保每個學(xué)生的信息都被獨立存儲和引用。
正確輸出
修改后的代碼將產(chǎn)生預(yù)期的輸出:
pprof.cn => pprof.cn 測試 => 測試 博客 => 博客
總結(jié)
本例揭示了for…range循環(huán)中使用指針的潛在風(fēng)險。 理解迭代變量的復(fù)用機制,并在必要時創(chuàng)建副本,是避免此類問題的關(guān)鍵。 這對于Go語言開發(fā)者來說是一個重要的知識點。