Fix for-range Issue Again in Go 1.22

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

Go 1.22 resolves a long-standing for-range loop variable scoping issue that commonly caused unexpected behavior in concurrent code utilizing closures. Previously, the loop variable was reused across iterations, leading goroutines to capture the same memory address and often print the final value multiple times. The fix ensures the loop variable behaves as if declared fresh in each iteration, allowing closures to correctly capture the intended value. This crucial change only activates if the go.mod file specifies Go 1.22 or higher, a design decision that preserves backward compatibility while enabling new language features.

隨著 Go 1.22 的發布,Go 團隊解決了長期存在的問題,這個問題與for-range迴圈變數的作用域有關,一直以來都是撰寫併發程式碼的開發人員常見的陷阱。具體來說,問題在於for-range迴圈中的迴圈變數在每次迭代中都被重複使用,當涉及閉包時,就會導致意想不到的行為。

Go 1.22 之前的問題

考慮以下範例:

package forange

import "fmt"

func Do() {
    done := make(chan bool)
    values := []string{"a", "b", "c"}

    for _, v := range values {
        go func() {
            fmt.Println(v) // 輸出非預期值
            done <- true
        }()
    }

    for _ = range values {
        <-done
    }
}

並且有一個go.mod檔案如下

module playground

go 1.16

require github.com/ozgio/strutil v0.4.0

在 Go 1.22 之前的版本中,執行此程式碼通常會導致多次列印相同的值(例如,c),而不是按預期列印values中的每個值(abc)。這是因為迴圈變數v在每次迭代中都被重複使用,而 goroutines 擷取了相同的記憶體位址。

Go 1.22 的修正

Go 1.22 引進了對此行為的修正,方法是使迴圈變數的行為如同在每次迭代中都被重新宣告一樣。這表示每個閉包現在都應該正確地擷取其對應迭代的v值。

但是,如果您已升級到 Go 1.22,但仍然觀察到舊的、有問題的行為,那麼罪魁禍首可能是您的go.mod檔案。只有當go.mod檔案指定 Go 版本為1.22或更高版本時,此修正才會生效。此相依性是有意的,允許開發人員在需要時保留與舊有行為的向後相容性。

在您的go.mod中指定go 1.22並應用修正後,執行上述程式應該會正確列印 a、b、c。每個 goroutine 現在都會擷取其迭代的正確v值。

經驗教訓

  • 保持更新:始終閱讀新 Go 版本的發行說明。Go 1.22 發行說明特別提到此更改及其對go.mod的相依性。
  • 使用正確的go.mod版本控制:許多 Go 語言功能都與go.mod中的go版本相關聯。如果您依賴新功能或修正,請確保指定正確的版本。
  • 徹底測試:即使在升級 Go 之後,也請透過執行全面的測試來確保您的程式按預期執行。

為什麼需要此相依性?

go.mod版本控制方法允許團隊逐步採用修正,而不會破壞現有的建置。透過將新的語言行為與go.mod中的go版本耦合,Go 團隊確保了向後相容性,同時也為開發人員提供了更順暢的遷移。

如果您遇到類似的挑戰,或對這如何影響您的工作流程有任何見解,請隨時在評論中分享!

BUG GO FOR RANGE GO.MOD GO 1.22

  RELATED

  COMMENT

1
xieyonglin
Nov 21, 2024 at 6:43 am

Nice article?