Материал проходит вычитку — возможны неточности.
Урок 58 из 118

Переменная цикла до 1.22

В «Полке» жил древний баг: фоновый логгер в цикле по файлам писал в журнал один и тот же путь. Миша взялся за разбор и к вечеру нашёл причину в старом коде, который никто не трогал годами.

Главная мысль

до Go 1.22 все итерации for делили одну переменную цикла: последнее значение гарантированно видели только замыкания, вызванные после цикла, а горутина, стартующая внутри цикла, могла увидеть промежуточное — и это гонка данных. Лечилось v:= v или передачей аргументом.

Замыкания в цикле

До Go 1.22 в for i:= 0; i < 3; i++ переменная i была одна на весь цикл. Замыкания, захватившие её, после цикла видели последнее значение:

<!-- wp:code-run/run {"code":"var funcs []func() int\nfor i := 0; i

Две классические починки

Первый способ — скопировать переменную в теле цикла: i:= i вводит новую переменную на каждой итерации.

for i := 0; i < 3; i++ {
    i := i
    funcs = append(funcs, func() int { return i })
}

Второй — передать значение аргументом: аргумент копируется при вызове.

for i := 0; i < 3; i++ {
    funcs = append(funcs, func(n int) func() int {
        return func() int { return n }
    }(i))
}

С for range история та же: до 1.22 одна переменная v на все итерации — последний элемент гарантированно видели только замыкания, вызванные после цикла, а захват в горутине мог дать промежуточный элемент, и это гонка данных.

Почему это вообще было багом

Семантика была такой с первой версии языка и жила больше десяти лет, но каждый год ломала новичков — баг был настолько частым, что в 1.22 поведение поменяли. Логгер «Полки» — живое подтверждение: код, написанный по старым правилам, годами писал в журнал не тот путь. Об этом — следующий урок.

Вы узнаете:

  • почему &i до 1.22 — одна и та же ячейка
  • как range по слайсу до 1.22 копировал заголовок
<!-- wp:course-hub/quiz {"title":"Проверьте себя","questions":[{"text":"До Go 1.22: три замыкания в цикле for i := 0; i

До 1.22: одна переменная цикла на все итерации; последнее значение видели замыкания, вызванные после цикла, а горутина внутри цикла — промежуточное, в гонке данных. Починки: i := i или аргумент.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки