What is variable capture in the context of Go programming?
sobes.tech AI
Answer from AI
Variable capturing in Go occurs when a closure function references a variable from its outer environment. Instead of copying the variable's value at the time of closure creation, the closure captures the variable itself. This means that if the variable's value changes after the closure is created but before it is called, the closure will use the new, changed value.
This is especially important when working with goroutines in loops. A classic problem arises when goroutines are created inside a loop, each using the loop variable. By the time the goroutine executes, the loop may have finished, and all goroutines will reference the same last value of the loop variable.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Incorrect capture:")
for i := 0; i < 5; i++ {
go func() { // Captures variable i
fmt.Printf("%d ", i) // By the time the goroutine runs, i might be 5
}()
}
time.Sleep(time.Second) // Allow goroutines to execute
fmt.Println("\nCorrect capture:")
for i := 0; i < 5; i++ {
j := i // Create a new variable for each loop iteration
go func() {
fmt.Printf("%d ", j) // Captures variable j
}()
}
time.Sleep(time.Second) // Allow goroutines to execute
fmt.Println()
}
The solution to this problem in a loop is to create a local copy of the loop variable inside each iteration, which the goroutine closure then captures.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Correct capture with argument passing:")
for i := 0; i < 5; i++ {
go func(val int) { // Pass the value as an argument
fmt.Printf("%d ", val) // Captures the argument val
}(i) // Pass the current value of i
}
time.Sleep(time.Second) // Allow goroutines to execute
fmt.Println()
}
Another way is to pass the variable as an argument to an anonymous function. In this case, each closure captures the value of the passed argument at the moment of the goroutine call.
Thus, variable capturing in Go is a mechanism where a closure function references a variable from the outer scope by reference, not by value at the time of closure creation.