В Go переменная цикла
for ... range создаётся заново на каждой итерации. Это снимает одну из самых частых проблем при работе с горутинами и замыканиями, когда несколько функций случайно ссылаются на одно и то же значение. Разберём как этим пользоваться.Замыкание захватывает не значение переменной, а саму переменную. Если бы
v была одна на весь цикл, все запущенные горутины ссылались бы на общую ячейку и видели бы её последнее значение. Поскольку в Go у каждой итерации своя
v, такого не происходит:for _, v := range data {
go func() { fmt.Println(v) }()
}
Каждая горутина печатает значение своей итерации, а не последний элемент
data. Никаких обходных приёмов внутри тела цикла для этого не нужно.На каждом проходе компилятор заводит новую переменную и копирует в неё текущее значение. Замыкание, которое вы создаёте внутри тела, привязывается именно к этой копии. Когда итерация заканчивается, её переменная остаётся жить ровно столько, сколько на неё ссылаются запущенные функции.
То же касается и индекса в форме с двумя переменными:
for i, v := range items {
go func() {
fmt.Println(i, v)
}()
}И
i, и v уникальны для каждого прохода, поэтому пара значений всегда соответствует своей итерации.Поведение привязано к версии языка в директиве
go файла go.mod. Оно действует, когда там указано go 1.22 или выше. Если в модуле прописана версия старше, тот же код соберётся со старой семантикой даже на новом компиляторе. Так одна и та же кодовая база ведёт себя предсказуемо, а апгрейд тулчейна не меняет логику молча.ℹ️ О чём помнить
Копия создаётся под каждую итерацию, но это именно копия значения. Если в
v лежит срез или указатель, копируется он, а не данные за ним, и общий доступ к этим данным из горутин по-прежнему требует синхронизации. Свойство решает проблему захвата переменной, а не гонок по самим данным.Опираться на это можно в любом коде, где замыкания и горутины создаются внутри
for ... range. Значение каждой итерации остаётся при ней, и писать переобъявление внутри тела больше не требуется.📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoDeep