Go

What does this print in Go 1.22+ vs before?

Question 236MediumGo 1.22 to 1.25
func main() {
	var wg sync.WaitGroup
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Print(i, " ")
		}()
	}
	wg.Wait()
}

Go 1.22 and later (when go.mod declares go 1.22 or higher): each iteration gets its own i. The output is some permutation of 0 1 2, in any order because goroutine scheduling is nondeterministic.

Before Go 1.22, a single i was shared by every iteration. It typically printed 3 3 3, and it was also a data race, since the loop wrote i while the goroutines read it. The old workaround was i := i or passing i as an argument.

Notes:

  • The semantics are chosen per module by the go line in go.mod, not by the toolchain version. Old modules built with a new compiler keep the old behavior.
  • The change applies to 3-clause for loops and to range loops.
  • The loopclosure vet check is no longer needed for 1.22+ modules.

Follow-up: if the output must be in order, ordering has to come from synchronization, for example by writing into results[i] and printing after Wait.

More on Concurrency Patterns & sync

All 38 Concurrency Patterns & sync questions