Как горутины обрабатывают переменную цикла при захвате

С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.

Короткий ответ

Что ответить на собеседовании

С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.

Подробный разбор

Ответ с пояснениями

Условие

Какой вывод будет у следующей программы?

func main() {
 wg := sync.WaitGroup{}

 for i := 0; i < 10; i++ {
  wg.Add(1)
  go func() {
   fmt.Println(i)
   wg.Done()
  }()
 }

 wg.Wait()
}

Ответ

С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.

WaitGroup обеспечивает завершение Println до выхода main, но не порядок. В старой семантике цикл изменяет общую i одновременно с чтением в горутинах.

Универсальное решение: go func(i int) { defer wg.Done(); fmt.Println(i) }(i). Новая семантика относится к объявленным переменным цикла и зависит от языковой версии модуля. Даже после исправления захвата порядок 0, 1, 2 и далее требует отдельной координации.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее