What does this print before and after Go 1.22? (taking &v and capturing i in loops)
Question 72HardGo 1.22 to 1.25
var ptrs []*int
for _, v := range []int{1, 2, 3} {
ptrs = append(ptrs, &v)
}
var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func() { fmt.Print(i, " ") })
}
for _, p := range ptrs {
fmt.Print(*p, " ")
}
fmt.Println()
for _, f := range funcs {
f()
}
Output with Go 1.22+ semantics:
1 2 3
0 1 2
Output with Go 1.21 and earlier semantics:
3 3 3
3 3 3
Before 1.22, a for loop declared its variables once for the whole loop. Every &v and every closure pointed at the same variable, which held its final value after the loop. For the three-clause loop that is 3, the value that ended the loop. Since Go 1.22 each iteration gets a fresh copy of the variable. In a three-clause loop, the new copy starts with the value the previous iteration ended with, before the post statement runs.
Details interviewers probe:
- The behaviour depends on the
goline ingo.mod(1.22 or later), not on the toolchain. An old module built with a new compiler keeps the old semantics. A file can also be pinned with a//go:build go1.21constraint. - The compiler allocates a fresh variable per iteration only when it escapes (it is captured or has its address taken), so ordinary loops cost nothing extra.
- Building with
-gcflags=all=-d=loopvar=2lists every loop whose semantics changed. To find which loop breaks a test, usegolang.org/x/tools/cmd/bisectwith-d=loopvarhash=PATTERN. &vstill points to a copy of the element, not into the slice. Use&s[i]to alias the element.
More on Arrays, Slices, Maps & Strings
- Q70How do you convert between []byte and string without copying, and what are the risks?
- Q71How do you implement a set in Go, and what maps package helpers exist?
- Q73What does this print? (map of slices built from a shared base)
- Q74What does this print? (range over a nil pointer to an array, and range over an int)
- Q75How do range-over-func iterators work on slices and maps, and what happens if an iterator ignores yield's return value?
- Q76What is the unique package (Go 1.23), and how does it help with memory for repeated strings?