Go 語(yǔ)言史詩(shī)級(jí)更新-循環(huán)Bug修復(fù)
背景
前兩天 Golang 的官方博客更新了一篇文章:Fixing For Loops in Go 1.22
看這個(gè)標(biāo)題的就是修復(fù)了 Go 循環(huán)的 bug,這真的是史詩(shī)級(jí)的更新;我身邊接觸到的大部分 Go 開發(fā)者都犯過(guò)這樣的錯(cuò)誤,包括我自己,所以前兩年我也寫過(guò)類似的博客:簡(jiǎn)單的 for 循環(huán)也會(huì)踩的坑
先來(lái)簡(jiǎn)單回顧下使用使用 for 循環(huán)會(huì)碰到的問(wèn)題:
list := []*Demo{{"a"}, {"b"}}
for _, v := range list {
go func() {
fmt.Println("name="+v.Name)
}()
}
type Demo struct {
Name string
}預(yù)期的結(jié)果應(yīng)該是打印 a,b,但實(shí)際打印的卻是b,b。
圖片
Let's Encrypt: CAA Rechecking bug類似的問(wèn)題連 mozilla 團(tuán)隊(duì)也沒(méi)能幸免,所以也確實(shí)是一個(gè)非常常見的問(wèn)題,這樣的寫法符合大部分的開發(fā)者的直覺(jué),畢竟其他語(yǔ)言這么使用也沒(méi)有問(wèn)題。
當(dāng)然在現(xiàn)階段要解決也很簡(jiǎn)單,要么就是在使用之前先復(fù)制一次,或者使用閉包傳參:
// 復(fù)制
list := []*Demo{{"a"}, {"b"}}
for _, v := range list {
temp:=v
go func() {
fmt.Println("name="+temp.Name)
}()
}
// 閉包
list := []*Demo{{"a"}, {"b"}}
for _, v := range list {
go func(temp *Demo) {
fmt.Println("name="+temp.Name)
}(v)
}還好官方也意識(shí)到了這個(gè)問(wèn)題:
圖片
所以在 1.22 中我們可以不用再寫這個(gè) ????v:=v這個(gè)多余的復(fù)制語(yǔ)句了,也不會(huì)出現(xiàn)上面的問(wèn)題。
我們?cè)?1.21 中可以使用環(huán)境變量預(yù)覽這個(gè)特性:
? GOEXPERIMENT=loopvar go test
name=b
name=a在 1.22 發(fā)布后建議大家都可以升級(jí)了,將這種惡心的 bug 扼殺在搖籃里。
1.22 后帶來(lái)了一個(gè)好消息是今后少了一道面試題,壞消息是又新增了一個(gè) 1.22 版本帶來(lái)了哪些變化的面試題??
更多詳情可以參看官方播客:https://go.dev/blog/loopvar-preview
































