Что изменилось с переменной цикла в Go 1.22?
- Почему все горутины в цикле печатали одно и то же значение?
До Go 1.22 переменная цикла for i := ... была одна на весь цикл: замыкания и горутины, захватившие её, видели последнее значение. С Go 1.22 каждая итерация получает свою копию — классическая ошибка исчезла (для модулей с go 1.22 в go.mod).
- Старое исправление: i := i внутри цикла или передача аргументом
- Поведение зависит от версии в go.mod, а не компилятора
- То же касается for k, v := range
А ещё В Python та же ловушка позднего связывания осталась
Подробно
Почему было так. Цикл переиспользовал одну переменную, меняя её значение. Замыкание захватывает переменную, а не значение; горутины стартуют позже, чем цикл успевает пройти дальше.
Изменение 1.22 (предложение Расса Кокса) сделало переменную на итерацию. Чтобы не сломать старый код, правило включается по версии языка в go.mod. Инструмент loopclosure в go vet ловил старую ошибку.
На собеседовании этот вопрос проверяет понимание замыканий и того, что горутина выполняется позже места запуска.
Пример
for _, url := range urls {
go func() {
fetch(url) // Go 1.22+: своя url на итерацию
}() // до 1.22: все горутины могли взять последнюю
}Что хотят услышать
- Старое поведение и его причина.
- Что изменилось и как включается.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗В Go 1.22 переменную цикла запретили захватывать в замыкания
- ✓Каждая итерация получает свою копию переменной цикла
- ✗Поведение зависит от версии компилятора, а не от строки go в go.mod
- ✗До Go 1.22 каждая итерация уже имела свою переменную
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.