Go 1.22 起迴圈變數每次疊代各自一份
舊教學都會說「
for i, v := range的v是同一個變數被反覆賦值,所以存&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(用最新版)與公司專案裡結果會不同。