Go 1.22 起迴圈變數每次疊代各自一份

舊教學都會說「for i, v := rangev 是同一個變數被反覆賦值,所以存 &v 會拿到一堆指向同一個位址的指標」。Go 1.22 之後這件事不再成立——迴圈變數改成每次疊代各自一份(per-iteration scope)。

intValues := []int{1, 3, 5}
ptrs := make([]*int, len(intValues))
for i, v := range intValues {
    ptrs[i] = &v
}
fmt.Println(*ptrs[0], *ptrs[1], *ptrs[2])
  • Go 1.21 以前 → 5 5 5(三個指標都指向同一個 v,迴圈結束時它是 5)
  • Go 1.22 以後 → 1 3 5(實測確認)

所以舊文章教的 &intValues[i]createWorkerFor(&versions[i]) 從「必須」降級為「Go 1.21 以前必須」。

但版本不是看編譯器,是看 go.mod

新版 Go 依 go.mod 裡宣告的 go 1.xx 決定套用哪套語意。在寫著 go 1.21 的舊專案裡,即使用 Go 1.24 編譯,跑出來仍然是 5 5 5

判斷順序:先看 go.mod 的那一行,不是 go version

這也是為什麼同樣的程式在 Go Playground(用最新版)與公司專案裡結果會不同。

相關:Go 的 range 回傳 index 與 valueGo 的 & 取址與 * 解參考