Home >Backend Development >Golang >Why Does Go Require Explicit Copying of Loop Variables in Closures?
Captured Closure in Go (for Loop Variables)
The Go compiler does not automatically capture for...range loop variables as locally assigned closure variables. Instead, Go treats all for loops (including for...range loops) similarly, requiring explicit copying of loop variables into local closures to ensure the expected behavior.
Reasoning for Copying Loop Variables
This behavior stems from Go's consistent handling of for loops. In all types of for loops, including for...range loops, loop variables are scoped to the block of the loop. After the loop's block ends, the loop variable is no longer accessible.
In for...range loops, the loop variable is initialized to a new value for each iteration of the loop. However, the closure created within the loop continues to reference the original loop variable. To ensure that the closure has an independent copy of the loop variable, it must be assigned to a local variable within the closure.
Code Example
Below is an example that illustrates the need for copying loop variables:
func main() { m := make(map[int32]int32) for i := int32(1); i <= 10; i++ { m[i] = i } l := make([]func() (int32, int32), 0) for k, v := range m { l = append(l, func() (int32, int32) { return k, v }) } for _, f := range l { k, v := f() fmt.Println(k, v) } }
In this example, the loop variable k is expected to change during each iteration of the for...range loop. However, the closure captures the original loop variable k, which remains the same throughout the loop. As a result, the code prints the same pair of values (10, 10) ten times.
Solution: Copying Loop Variables
To fix the issue, the loop variables must be copied into local variables within the closure:
func main() { m := make(map[int32]int32) for i := int32(1); i <= 10; i++ { m[i] = i } l := make([]func() (int32, int32), 0) for k, v := range m { kLocal, vLocal := k, v l = append(l, func() (int32, int32) { return kLocal, vLocal }) } for _, f := range l { k, v := f() fmt.Println(k, v) } }
Now, the closure captures the local variables kLocal and vLocal, which independently hold the values assigned during each iteration of the for...range loop. The code correctly prints the expected pairs of values (1, 1), (2, 2), ..., (10, 10).
The above is the detailed content of Why Does Go Require Explicit Copying of Loop Variables in Closures?. For more information, please follow other related articles on the PHP Chinese website!