How did loop variable semantics change in Go 1.22, and what does this print?
Question 35HardGo 1.22 to 1.25
var fns []func()
for i := 0; i < 3; i++ {
fns = append(fns, func() { fmt.Print(i, " ") })
}
for _, f := range fns {
f()
}
var ptrs []*int
for i := range 3 { // range over an int, Go 1.22
ptrs = append(ptrs, &i)
}
fmt.Println(*ptrs[0], *ptrs[1], *ptrs[2])
Output with Go 1.22 or later (when go.mod says go 1.22 or higher):
0 1 2 0 1 2
Before Go 1.22, both for forms had one loop variable for the whole loop. Every closure and every pointer referred to that same variable, so the first loop printed 3 3 3. Range-over-int did not exist before 1.22 (it needs go 1.22 or later in go.mod), but the equivalent old form for i := range []int{0, 1, 2} printed 2 2 2 for the pointer version. That was the most common Go bug, especially with goroutines started inside loops. Since Go 1.22, each iteration gets a new variable. In a three-clause loop, the value is copied into the next iteration's variable before the post statement runs, so changing i inside the body still affects how the loop progresses.
Points to raise:
- The behavior depends on the
goline in the module'sgo.mod, not on the compiler version you have installed. - Workarounds like
i := iare no longer needed. - If a pointer to the loop variable escapes, each iteration may now cost an allocation. Usually this is negligible.
for i := range nloops from 0 to n-1. The type ofimatches the type ofn.go vet'sloopclosurecheck is less relevant for newer modules.
More on Language Fundamentals & Types
- Q33Arrays vs slices as values: what does this print?
- Q34How does Go handle integer overflow, division, and conversions between numeric types?
- Q36How do range-over-func iterators (Go 1.23) work? What does this print?
- Q37How do struct field alignment and padding work? What are the sizes of these structs?
- Q38What is the difference between a method value and a method expression? What does this print?
- Q39What type does an untyped constant take in a non-constant shift? What does this print?