In Go, the compiler can automatically capture loop variables for use within closures, but this behavior varies depending on the type of loop. In for...range loops, the loop variables are captured as references to the outer loop's iteration variables.
Go treats for...range loops and other for loops similarly. Therefore, the captured closure for a loop variable in a for...range loop references the same memory location as the outer loop's variable.
In this scenario, any modifications made to the captured closure's variable also affect the outer loop's variable, potentially leading to unexpected behavior. To avoid this issue, it's necessary to create a copy of the loop variable within the closure, as shown in the "Value...range" example below.
The provided code snippet illustrates the difference between capturing a reference to the loop variable versus capturing its value:
func main() { lab1() // captured closure is not what is expected lab2() // captured closure is not what is expected lab3() // captured closure behaves ok } func lab3() { m := make(map[int32]int32) for i := 1; i <= 10; i++ { m[i] = i } l := [](func() (int32, int32)){} for k, v := range m { kLocal, vLocal := k, v // (C) captures just the right values assigned to k and v l = append(l, func() (int32, int32) { return kLocal, vLocal }) } for _, x := range l { k, v := x() fmt.Println(k, v) } } func lab2() { m := make(map[int32]int32) for i := 1; i <= 10; i++ { m[i] = i } l := [](func() (int32, int32)){} for k, v := range m { l = append(l, func() (int32, int32) { kLocal, vLocal := k, v // (B) captures just the last values assigned to k and v from the range return kLocal, vLocal }) } for _, x := range l { k, v := x() fmt.Println(k, v) } } func lab1() { m := make(map[int32]int32) for i := 1; i <= 10; i++ { m[i] = i } l := [](func() (int32, int32)){} for k, v := range m { l = append(l, func() (int32, int32) { return k, v }) // (A) captures just the last values assigned to k and v from the range } for _, x := range l { k, v := x() fmt.Println(k, v) } }
In lab1, the captured closures reference the final values from the loop instead of the expected individual values. In lab2, the captures still reference the final values because the created closure uses the same loop variables that are being referenced elsewhere in the outer scope. In lab3, the closures capture copies of the loop variables, so they accurately represent the individual values.
The above is the detailed content of How Does Go Handle Captured Loop Variables in Closures, and Why Does it Matter?. For more information, please follow other related articles on the PHP Chinese website!