Go 語言史詩級更新-迴圈Bug修復

發表於2023-09-27

背景

前兩天 Golang 的官方部落格更新了一篇文章:Fixing For Loops in Go 1.22

看這個標題的就是修復了 Go 迴圈的 bug,這真的是史詩級的更新;我身邊接觸到的大部分 Go 開發者都犯過這樣的錯誤,包括我自己,所以前兩年我也寫過類似的部落格:
簡單的 for 迴圈也會踩的坑

先來簡單回顧下使用使用 for 迴圈會碰到的問題:

list := []*Demo{{"a"}, {"b"}}  
for _, v := range list {  
    go func() {  
        fmt.Println("name="+v.Name)  
    }()  
}  
  
type Demo struct {  
    Name string  
}

預期的結果應該是列印 a,b,但實際列印的卻是b,b

image.png

Let's Encrypt: CAA Rechecking bug
類似的問題連 mozilla 團隊也沒能倖免,所以也確實是一個非常常見的問題,這樣的寫法符合大部分的開發者的直覺,畢竟其他語言這麼使用也沒有問題。

當然在現階段要解決也很簡單,要麼就是在使用之前先複製一次,或者使用閉包傳參:

 // 複製
 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)  
 }

還好官方也意識到了這個問題:
image.png
所以在 1.22 中我們可以不用再寫這個 



v:=v這個多餘的複製語句了,也不會出現上面的問題。

我們在 1.21 中可以使用環境變數預覽這個特性:

❯ GOEXPERIMENT=loopvar go test
name=b
name=a

在 1.22 釋出後建議大家都可以升級了,將這種噁心的 bug 扼殺在搖籃裡。

1.22 後帶來了一個好訊息是今後少了一道面試題,壞訊息是又新增了一個 1.22 版本帶來了哪些變化的面試題?

更多詳情可以參看官方播客:https://go.dev/blog/loopvar-preview

相關文章