gotchagoMajorpending
Gotcha: Go goroutine variable capture in loops
Viewed 0 times
goroutineclosureloop variablecapturerange
Error Messages
Problem
Goroutines launched in a loop all see the same (last) value of the loop variable.
Solution
Loop variable capture issue and fixes:
This also affects defer, not just goroutines:
// BUG (Go < 1.22): All goroutines print the last value
for _, url := range urls {
go func() {
fetch(url) // url is shared, always the last value!
}()
}
// FIX 1: Pass as parameter (works in all Go versions)
for _, url := range urls {
go func(u string) {
fetch(u) // u is a copy, correct value
}(url)
}
// FIX 2: Shadow the variable (works in all Go versions)
for _, url := range urls {
url := url // Creates new variable in loop scope
go func() {
fetch(url) // This url is the shadowed copy
}()
}
// Go 1.22+: Fixed! Each iteration gets its own variable
// The original code works correctly in Go 1.22+
for _, url := range urls {
go func() {
fetch(url) // Correct in Go 1.22+
}()
}This also affects defer, not just goroutines:
for _, f := range files {
file, _ := os.Open(f)
defer file.Close() // In Go < 1.22, closes same file N times
}Why
Before Go 1.22, for-range loop variables were declared once and updated each iteration, so closures captured a reference to the same variable.
Context
Go code launching goroutines or using closures in loops
Revisions (0)
No revisions yet.