In Go, closures are functions that "enclose" (capture) variables from their surrounding scope. Closures are most commonly used for anonymous functions created inside other functions.
The most typical problem when working with closures is unexpected behavior when using loop variables inside a goroutine:
for i := 0; i < 3; i++ { go func() { fmt.Println(i) }() }
Each goroutine may print the same value of i, because the variable i is looping, and the closure captures the variable itself, not its value at each iteration.
Correct way:
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
This behavior is related to the fact that the closure holds a reference to the variable (its address), not its sliced (by value) value.
What value will several launched goroutines print inside a loop if they capture the loop variable?
Answer: All goroutines may print the same value (often the last one), as they see the current value of the variable, and by the time the goroutine is executed, the loop has already ended. To avoid this, the variable needs to be passed as a parameter to the closure.
Example:
for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } // most likely we will get: 5 5 5 5 5
Story
Story
Story
In a courier startup, incorrect use of closures when updating order coordinates led to mass updates of the last order's coordinates in the slice, rather than the current one — due to a race condition when accessing the slice inside the anonymous function.