Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Задачи

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Golang: Go, goroutine, closure, loop variable capture, Go 1.22

Почему при итерации по map в цикле и запуске горутин с захватом переменной цикла до Go 1.22 возникала проблема?

Проверяет понимание захвата переменных цикла горутинами в Go и изменения в Go 1.22.

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

До Go 1.22 переменная цикла в for range создавалась один раз и переиспользовалась на каждой итерации. Горутины захватывали ссылку на одну и ту же переменную, а не её значение на момент запуска. К моменту выполнения горутины переменная уже могла измениться, что приводило к неожиданным результатам. В Go 1.22 переменная цикла создаётся заново на каждой итерации, что решает проблему.

Длинный ответ

Проблема захвата переменной цикла горутинами

В Go до версии 1.22 переменная, объявленная в цикле for range, создавалась один раз и переиспользовалась на каждой итерации. Это означало, что все горутины, запущенные внутри цикла, захватывали ссылку на одну и ту же переменную, а не её значение на момент запуска. Когда горутина начинала выполняться (возможно, после завершения цикла), переменная уже содержала последнее значение итерации, что приводило к неожиданным результатам.

Пример проблемы

package main

import (
	"fmt"
	"time"
)

func main() {
	m := map[int]string{1: "a", 2: "b", 3: "c"}
	for k, v := range m {
		go func() {
			fmt.Println(k, v) // захватывает ссылку на k и v
		}()
	}
	time.Sleep(time.Second)
}

В этом примере вывод может быть неопределённым: все горутины могут напечатать последнюю пару ключ-значение из map, так как переменные k и v переиспользуются.

Решение до Go 1.22

Разработчики обходили проблему, создавая локальную копию переменной внутри цикла:

for k, v := range m {
	k := k // создаём копию
	v := v
	go func() {
		fmt.Println(k, v)
	}()
}

Изменения в Go 1.22

Начиная с Go 1.22, переменные цикла создаются заново на каждой итерации, что делает захват безопасным по умолчанию. Теперь приведённый выше код без копирования работает корректно.

Вывод

Понимание этой проблемы важно для написания корректного конкурентного кода на Go. Хотя Go 1.22 исправил поведение, знание старого механизма помогает читать и поддерживать legacy-код, а также избегать подобных ошибок в других языках с аналогичным поведением.

  • Аватар

    Golang Guru

    Maxim Lukyanov

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.

Уровень

  • Рейтинг:

    4

  • Сложность:

    5

Навыки

  • Golang

    Golang

Ключевые слова

#Go

#goroutine

#closure

#loop variable capture

#Go 1.22

Подпишись на Golang Developer в телеграм

  • Аватар

    Golang Guru

    Maxim Lukyanov

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.