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

Go 1.22 и миграция

Команда решилась на миграцию на Go 1.22. Заодно пересмотрели старые «фиксы» логгера: часть из них больше не была нужна. Старый баг исчез вместе со старой семантикой.

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

с Go 1.22 переменная, объявленная в заголовке for через :=, своя на каждой итерации — включается это версией go.mod, для старых модулей код ведёт себя по-старому, и i:= i остаётся верным на обеих семантиках.

Новое поведение

На Go 1.22+ тот же код из прошлого урока даёт ожидаемый результат:

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

В for i:= 0; i < n; i++ первая итерация использует переменную из инициализации, а перед пост-инструкцией (i++) заводится свежая переменная для следующей итерации. Поэтому обычные идиомы вроде прохода по s[i] не изменились — разница видна только там, где i захватывается замыканием или у неё берут адрес. Важно: правило касается только переменных, объявленных в заголовке через :=. Заранее объявленная переменная, которой присваивают через = (var i int; for i = 0;...), остаётся одной на все итерации на любой версии языка.

Семантику включает go.mod

Изменение не включается просто новой версией компилятора. Поведение привязывается к версии языка, объявленной в go.mod: go 1.22 — новая семантика, go 1.21 и ниже — старая, даже если компилятор свежий. Это сделано, чтобы обновление тулчейна не меняло поведение работающего кода.

Что писать в общем коде

i:= i работает на обеих семантиках — явная копия переменной ничему не мешает. Если библиотека собирается под старыми версиями или вы просто не хотите зависеть от версии go.mod — ставьте i:= i. Для проверки старого поведения правку go.mod не обходят: надёжный способ — модуль с go 1.21. Флаг GOEXPERIMENT=loopvar направлен в другую сторону: он включает новую семантику (на Go 1.21 был её предпросмотром), а GOEXPERIMENT=noloopvar на современных тулчейнах не действует — откатом его не считают. Всё это — инструменты миграции, а не рабочий режим.

Вы узнаете:

  • как переменная range ведёт себя в 1.22
  • как проверить старое поведение через GOEXPERIMENT и go.mod
<!-- wp:course-hub/quiz {"title":"Проверьте себя","questions":[{"text":"Замыкания в цикле for i := 0; i < 3; i++ возвращают i. От чего зависит вывод — 333 или 012?","options":[{"text":"От версии языка в go.mod: go 1.22+ → 012, go 1.21 и ниже → 333, даже на свежем тулчейне","correct":true,"comment":"Семантику задаёт go.mod, а не версия компилятора — чтобы обновление тулчейна не меняло поведение."},{"text":"От версии компилятора","correct":false},{"text":"От числа итераций","correct":false},{"text":"Всегда 012 на любом тулчейне","correct":false}]},{"text":"Какие переменные цикла стали «своими на каждой итерации» в Go 1.22?","options":[{"text":"Только объявленные в заголовке через := ; заранее объявленная с = остаётся общей","correct":true,"comment":"var i int; for i = 0; ... остаётся одной на все итерации на любой версии языка."},{"text":"Все переменные цикла","correct":false},{"text":"Только переменные range","correct":false},{"text":"Только целочисленные счётчики","correct":false}]},{"text":"Почему идиома for i := 0; i

Go 1.22: своя переменная на каждой итерации — но только объявленная в заголовке через := (заранее объявленная с = — общая); включается версией go.mod; i := i корректен везде.

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