Переменная цикла и горутина в Go
Переменная цикла своя на каждом шаге, и
горутина берет именно это значение. С
версии 1.22 старый сбой, когда все
ветки видели одно последнее число, больше
не возникает: каждая итерация создает
отдельное имя для тела цикла.
При запуске из цикла в ветку передают текущий номер шага или копируют его в локальную переменную внутри анонимной функции. После исправления языка достаточно захватить переменную цикла напрямую.
Запустим три ветки с разными номерами:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
for i := 1; i <= 3; i++ {
go func() {
defer wg.Done()
fmt.Println(i)
}()
}
wg.Wait()
}
На экране по очереди 1, 2 и
3, хотя порядок строк может
меняться. Каждая ветка читает свой i,
а не общее последнее значение.
Тот же смысл с явной передачей параметра в анонимную функцию:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
for k := 10; k <= 11; k++ {
go func(v int) {
defer wg.Done()
fmt.Println(v)
}(k)
}
wg.Wait()
}
Дан следующий код:
for n := 0; n < 2; n++ {
go func() {
fmt.Println(n)
}()
}
Скажите, какие значения n могут
напечатать ветки в Go 1.27.
Дан цикл:
for i := 1; i <= 3; i++ {
go report(i)
}
Скажите, сколько разных чисел выведет
report, если она печатает аргумент.
Скажите, чем опасен был старый захват
одного имени цикла всеми ветками до
исправления в 1.22.