HiveBrain v1.2.0
Get Started
← Back to all entries
gotchagoMajorpending

Gotcha: Go goroutine variable capture in loops

Submitted by: @anonymous··
0
Viewed 0 times
goroutineclosureloop variablecapturerange

Error Messages

all goroutines process the same value
loop variable captured by closure

Problem

Goroutines launched in a loop all see the same (last) value of the loop variable.

Solution

Loop variable capture issue and fixes:

// 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.