Captured for var in closure can change
Variables can be captured into anonymous functions in go with closures, and its easy to use the variables we declare in a for loop in those anonymous functions, but that doesn't produce the results I would expect.
var fnArray []func()
for _, chr := range []string{"a", "b", "c"} {
fmt.Println("Hello,", chr)
fn := func() {
fmt.Println("Goodbye,", chr)
}
fnArray = append(fnArray, fn)
}
for _, fn := range fnArray {
fn()
}
The above code outputs:
Hello,a
Hello,b
Hello,c
Goodbye,c
Goodbye,c
Goodbye,c
Go optimizes for loops by using the same memory space for each value that it terates over. To avoid this hard edge you can reassign that value:
capturedChr := chr
Inserted that assignment into our for loop looks like this:
var fnArray []func()
for _, chr := range []string{"a", "b", "c"} {
capturedChr := chr
fmt.Println("Hello,", chr)
fn := func() {
fmt.Println("Goodbye,", capturedChr)
}
fnArray = append(fnArray, fn)
}
for _, fn := range fnArray {
fn()
}
And produces this more correct output:
Hello,a
Hello,b
Hello,c
Goodbye,a
Goodbye,b
Goodbye,c
Checkout the go playground here
Tweet