For statements with
for
clause… The variable used by the first iteration is declared by the init statement. The variable used by each subsequent iteration is declared implicitly before executing the post statement and initialized to the value of the previous iteration’s variable at that moment.
So let’s break this down. In fact, the pseudo code I showed you during my earlier breakdown really more closely demonstrated the behavior prior to Go 1.22. So let’s be a bit more explicit with variable scoping this time.
i := 0 // initial statement
if i < 3 { // i == 0, 0 < 3 so execute the block
fmt.Println(i) // Prints 0
{
i := i // New `i` variable scoped to the new loop iteration
i++ // Post statement
if i < 3 { // i == 1, 1 < 3 so execute the block
fmt.Println(i) // Prints 1
{
i := i // New `i` variable scoped to the new loop iteration
i++ // Post statement
if i < 3 { // i == 2, 2 < 3 so execute the block
fmt.Println(i) // Prints 2
{
i := i // New `i` variable scoped to the new loop iteration
i++ // Post statement
if i < 3 { // i == 3, 3 is not less than 3, so the block does not execute, and the loop ends
/* not executed */
}
}
}
}
}
}
}
That’s kind of a mess. If it doesn’t make sense, don’t worry too much about it. This isn’t a literal representation of what’s happening (each loop iteration doesn’t create a nested scope—that’s just the easiest way to write the pseudo code).
var prints []func() for i := 0; i < 5; i++ { prints = append(prints, func() { println(i) }) i++ } for _, p := range prints { p() }
prints
1 3 5
Prior to [Go 1.22], iterations share one set of variables instead of having their own separate variables. In that case, the example above prints
6 6 6
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)