Go tests
14.07.2026 14:55 · 👁 751
👣 Go давно починил старую ловушку с замыканиями в цикле.
Но concurrency всё ещё может кусаться.
Что не так с этим кодом?
package main
import (
"fmt"
"sync"
)
func main() {
nums := []int{1, 2, 3, 4}
var wg sync.WaitGroup
result := make([]int, 0, len(nums))
for i, n := range nums {
wg.Go(func() {
result = append(result, i*n)
})
}
wg.Wait()
fmt.Println(result)
}
На первый взгляд всё нормально.
i и n уже не общие для всех итераций. В современном Go каждая итерация получает свои переменные, поэтому старого бага с замыканием тут нет.
Проблема в другом месте.
`append` меняет slice header и может трогать общий backing array. Несколько горутин делают это одновременно. Значит, здесь data race, даже если loop variables теперь безопасные.
Правильный вариант:
```go id="9f32ws"
package main
import (
"fmt"
"sync"
)
func main() {
nums := []int{1, 2, 3, 4}
var wg sync.WaitGroup
result := make([]int, len(nums))
for i, n := range nums {
wg.Go(func() {
result[i] = i * n
})
}
wg.Wait()
fmt.Println(result)
}
```
Теперь каждая горутина пишет в свой индекс.
Без mutex.
Без channel.
Без лишнего копирования переменных.
Хороший тест на то, понимаешь ли ты Go после 1.22, а не просто помнишь старую страшилку про closures.