Go編程中的陷阱:為什么代碼中輸出的名字都是“博客”?

Go編程中的陷阱:為什么代碼中輸出的名字都是“博客”?

go語(yǔ)言陷阱:循環(huán)指針的誤用導(dǎo)致輸出全為“博客”

Go語(yǔ)言簡(jiǎn)潔高效,但其細(xì)微之處也容易造成困擾。本文剖析一個(gè)常見(jiàn)的Go語(yǔ)言面試題,解釋為何代碼輸出結(jié)果全部為“博客”。

以下代碼片段演示了這個(gè)問(wèn)題:

type student struct {     name string     age  int }  func main() {     m := make(map[string]*student)     stus := []student{         {name: "pprof.cn", age: 18},         {name: "測(cè)試", age: 23},         {name: "博客", age: 28},     }      for _, stu := range stus {         m[stu.name] = &stu     }     for k, v := range m {         fmt.Println(k, "=>", v.name)     } }

運(yùn)行結(jié)果令人意外:所有輸出均為“博客”。究其原因,在于for…range循環(huán)及指針的用法。

問(wèn)題根源:循環(huán)變量復(fù)用與指針指向

  1. 循環(huán)變量復(fù)用: Go語(yǔ)言的for…range循環(huán)會(huì)復(fù)用循環(huán)變量stu。這意味著stu始終指向同一內(nèi)存地址。

  2. 指針引用: 代碼中m[stu.name] = &stu使用指針,每次迭代都將stu的內(nèi)存地址賦值給map。由于stu的地址不變,所有map的值都指向同一地址。

  3. 最后一次賦值: 循環(huán)結(jié)束后,stu保存了最后一個(gè)學(xué)生的信息(“博客”)。因此,map中所有鍵值都指向這個(gè)最終的stu地址。

  4. 輸出結(jié)果: 打印v.name時(shí),所有指針都指向同一個(gè)“博客”數(shù)據(jù),故輸出結(jié)果全為“博客”。

解決方案:避免指針直接引用循環(huán)變量

為了避免此問(wèn)題,應(yīng)在循環(huán)內(nèi)創(chuàng)建新的student結(jié)構(gòu)體副本,而不是直接使用stu的指針:

for _, stu := range stus {     s := stu // 創(chuàng)建副本     m[stu.name] = &s }

這樣,每個(gè)map的鍵值對(duì)都指向不同的內(nèi)存地址,從而正確輸出每個(gè)學(xué)生的名字。

總結(jié):謹(jǐn)慎使用指針和理解循環(huán)變量

此例警示我們?cè)贕o語(yǔ)言中使用指針時(shí)需格外謹(jǐn)慎,尤其在循環(huán)和切片操作中。理解for…range循環(huán)的變量復(fù)用機(jī)制是避免此類(lèi)問(wèn)題的關(guān)鍵。 避免直接將循環(huán)變量的地址賦值給map或其他數(shù)據(jù)結(jié)構(gòu),而是創(chuàng)建副本后再使用指針,是更安全的做法。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊10 分享