Примечания к выпуску Go 1.22

Введение в Go 1.22

Последний выпуск Go, версия 1.22, появился через шесть месяцев после Go 1.21. Большая часть его изменений касается реализации инструментария, среды выполнения и библиотек. Как и всегда, выпуск сохраняет обещание совместимости Go 1. Ожидается, что почти все программы на Go продолжат компилироваться и выполняться так же, как и раньше.

Изменения в языке

Go 1.22 вносит два изменения в циклы «for».

  • Ранее переменные, объявленные в цикле «for», создавались один раз и обновлялись на каждой итерации. В Go 1.22 каждая итерация цикла создаёт новые переменные, чтобы избежать случайных ошибок, связанных с совместным использованием. Инструменты перехода, описанные в предложении, продолжают работать так же, как и в Go 1.21.

  • Циклы «for» теперь могут использовать «range» с целыми числами. Пример:

    <code>package main
    
    import "fmt"
    
    func main() {
      for i := range 10 {
        fmt.Println(10 - i)
      }
      fmt.Println("go1.22 has lift-off!")
    }
    </code>

    См. спецификацию по подробностям.

Go 1.22 включает предварительную версию изменения языка, которое мы рассматриваем для будущих версий Go: range-перебор по функциям-итераторам. Для включения этой функции необходимо собирать проект с флагом GOEXPERIMENT=rangefunc.

Инструменты

Команда go

Команды в пространствах имён теперь могут использовать каталог vendor, содержащий зависимости пространства имён. Каталог создаётся с помощью go work vendor, и используется командами сборки, когда флаг -mod установлен в значение vendor, которое является значением по умолчанию, если в пространстве имён существует каталог vendor.

Обратите внимание, что содержимое каталога vendor для пространства имён отличается от содержимого каталога vendor одного модуля: если каталог на корне пространства имён также содержит один из модулей этого пространства имён, его каталог vendor может содержать зависимости либо пространства имён, либо модуля, но не обоих одновременно.

Команда go get больше не поддерживается вне модуля в устаревшем режиме GOPATH (то есть при GO111MODULE=off). Другие команды сборки, такие как go build и go test, будут продолжать работать бесконечно для программ в устаревшем режиме GOPATH.

Команда go mod init больше не пытается импортировать требования модулей из конфигурационных файлов других инструментов управления зависимостями (например, Gopkg.lock).

Команда go test -cover теперь выводит сводку покрытия для покрытых пакетов, у которых нет собственных тестовых файлов. До Go 1.22 запуск go test -cover для таких пакетов выводил

? mymod/mypack [no test files]

а теперь в Go 1.22 функции в пакете считаются непокрытыми:

mymod/mypack coverage: 0.0% of statements

Обратите внимание, что если пакет не содержит исполняемого кода вообще, мы не можем вывести осмысленный процент покрытия; для таких пакетов инструмент go продолжит сообщать, что нет тестовых файлов.

Команды сборки go, которые вызывают компоновщик, теперь выдают ошибку, если будет использоваться внешний (C) компоновщик, но cgo не включён. (Среда выполнения Go требует поддержки cgo, чтобы гарантировать совместимость с дополнительными библиотеками, добавленными компоновщиком C.)

Trace

Веб-интерфейс инструмента trace был мягко обновлён как часть работы по поддержке нового трейсера, что позволило устранить несколько проблем и улучшить читаемость различных подстраниц. Веб-интерфейс теперь поддерживает просмотр трейсов в виде, ориентированном на потоки. Трейсер также теперь отображает полную продолжительность всех системных вызовов.
Эти улучшения применяются только для просмотра трейсов, созданных программами, собранными с использованием Go 1.22 или новее. В будущем выпуске некоторые из этих улучшений будут доступны и для трейсов, созданных более старыми версиями Go.

Vet

Ссылки на переменные цикла

Поведение инструмента vet было изменено для соответствия новой семантике (см. выше) переменных цикла в Go 1.22. При анализе файла, требующего Go 1.22 или новее (из-за его go.mod файла или per-file build constraint), vet больше не сообщает о ссылках на переменные цикла внутри функционального литерала, который может существовать дольше итерации цикла. В Go 1.22 переменные цикла создаются заново для каждой итерации, поэтому такие ссылки больше не представляют риска использования переменной после того, как она была обновлена циклом.

Новые предупреждения о пропущенных значениях после append

Инструмент vet теперь сообщает о вызовах функции append, которые не передают значения для добавления в срез, например slice = append(slice). Такая инструкция не имеет эффекта, и опыт показывает, что это почти всегда ошибка.

Новые предупреждения о defer-е time.Since

Инструмент vet теперь сообщает о вызове time.Since(t) вне defer выражения внутри defer инструкции. Это эквивалентно вызову time.Now().Sub(t) до defer инструкции, а не тогда, когда вызывается отложенная функция. В почти всех случаях, правильный код требует отложенного вызова time.Since. Например:

<code>t := time.Now()
defer log.Println(time.Since(t)) // неотложеный вызов time.Since
tmp := time.Since(t); defer log.Println(tmp) // эквивалентно предыдущему defer

defer func() {
  log.Println(time.Since(t)) // правильно отложенный вызов time.Since
}()
</code>

Новые предупреждения о несоответствии пар ключ-значение в вызовах log/slog

Инструмент vet теперь сообщает об ошибочных аргументах в вызовах функций и методов в пакете структурированного логирования, log/slog, которые принимают чередующиеся пары ключ/значение. Он сообщает о вызовах, где аргумент в позиции ключа не является string или slog.Attr, и где у последнего ключа отсутствует значение.

Runtime

Среда выполнения теперь хранит метаданные сборки мусора, основанные на типах, ближе к каждому объекту кучи, что улучшает производительность CPU (задержку или пропускную способность) программ на Go на 1–3%. Это изменение также снижает накладные расходы памяти для большинства программ на Go примерно на 1% благодаря дедупликации избыточных метаданных. Некоторые программы могут видеть меньшее улучшение, потому что это изменение корректирует границы классов размеров аллокатора памяти, поэтому некоторые объекты могут быть перемещены на следующий класс размера.

В результате этого изменения некоторые адреса объектов, которые ранее всегда выравнивались по 16-байтовой (или более высокой) границе, теперь будут выравниваться только по 8-байтовой границе. Некоторые программы, использующие инструкции ассемблера, требующие адресов памяти быть более чем 8-байтово выровненными и полагающиеся на предыдущее поведение аллокатора памяти, могут сломаться, но мы ожидаем, что такие программы будут редки. Такие программы могут быть собраны с помощью GOEXPERIMENT=noallocheaders, чтобы вернуться к старому макету метаданных и восстановить предыдущее поведение выравнивания, но владельцы пакетов должны обновить свой ассемблерный код, чтобы избежать предположения о выравнивании, так как этот обходной путь будет удалён в будущем выпуске.

В порте windows/amd64, программы, связывающиеся или загружающие библиотеки Go, собранные с использованием -buildmode=c-archive или -buildmode=c-shared, теперь могут использовать функцию Win32 SetUnhandledExceptionFilter для перехвата исключений, не обработанных средой выполнения Go. Обратите внимание, что это уже поддерживалось в порте windows/386.

Компилятор

Профайлинг-ориентированная оптимизация (PGO) теперь может более эффективно устранять виртуализацию вызовов по сравнению с предыдущими версиями. Большинство программ из репрезентативного набора программ на Go теперь получают прирост производительности от 2 до 14% при включении PGO.

Компилятор теперь чередует этапы устранения виртуализации и инлайна, что приводит к лучшей оптимизации вызовов методов интерфейсов.

Go 1.22 также включает предварительную версию улучшенной реализации фазы инлайна компилятора, использующей эвристику для повышения возможности инлайна в «важных» местах вызовов (например, внутри циклов) и снижения этой возможности в «незначительных» местах вызовов (например, на путях panic). Включение нового поведения осуществляется с помощью GOEXPERIMENT=newinliner; см. проблему #61502 для получения дополнительной информации и обратной связи.

Линкер

Флаги -s и -w линкера теперь ведут себя более последовательно на всех платформах. Флаг -w подавляет генерацию отладочной информации DWARF. Флаг -s подавляет генерацию таблицы символов. Флаг -s также неявно включает флаг -w, который может быть отменён с помощью -w=0. То есть, -s -w=0 будет генерировать бинарный файл с отладочной информацией DWARF, но без таблицы символов.

В платформах ELF флаг линкера -B теперь принимает специальный формат: при использовании -B gobuildid линкер будет генерировать GNU build ID (запись ELF NT_GNU_BUILD_ID), производную от Go build ID.

В Windows при сборке с -linkmode=internal линкер теперь сохраняет информацию SEH из C-объектных файлов, копируя секции .pdata и .xdata в итоговый бинарный файл. Это помогает при отладке и профилировании бинарных файлов с использованием нативных инструментов, таких как WinDbg. Обратите внимание, что ранее обработчики исключений SEH функций C не учитывались, поэтому это изменение может повлиять на поведение некоторых программ. -linkmode=external не затрагивается этим изменением, поскольку внешние линкеры уже сохраняют информацию SEH.

Bootstrap

Как указано в заметках о выпуске Go 1.20, Go 1.22 теперь требует финального патча Go 1.20 или более поздней версии для bootstrap. Ожидается, что Go 1.24 будет требовать финального патча Go 1.22 или более поздней версии для bootstrap.

Стандартная библиотека

Новый пакет math/rand/v2

Go 1.22 включает первый пакет "v2" в стандартной библиотеке, math/rand/v2. Изменения по сравнению с math/rand подробно описаны в предложении #61716. Наиболее важные изменения:

This is a comprehensive list of changes and new features introduced in **Go 1.22**, the latest stable release of the Go programming language at the time of writing. Below is a categorized summary of the key updates, grouped by package: --- ## 🧱 Core Language & Runtime ### Go 1.22 Language Features - **`reflect.TypeFor[T]()`**: A new function to get the `reflect.Type` of a type argument directly, replacing the older `reflect.TypeOf((*T)(nil)).Elem()` pattern. - **`reflect.PtrTo` deprecated**: Replaced by `reflect.PointerTo`. - **`reflect.Value.IsZero` improvements**: - Now returns `true` for negative zero floating-point and complex numbers. - Returns `true` for struct values with blank (`_`) fields that are non-zero. - **`slices.Concat`**: New function to concatenate multiple slices. - **Slice manipulation functions**: - `Delete`, `DeleteFunc`, `Compact`, `CompactFunc`, `Replace` now zero out elements between the new and old length. - `Insert` now always panics if index `i` is out of range, even when inserting no elements. --- ## 🧰 Standard Library Packages ### `os/exec` - On Windows: - `LookPath` ignores empty entries in `%PATH%`. - Returns `ErrNotFound` instead of `ErrNotExist` if no executable extension is found. - `Command` and `Cmd.Start` no longer call `LookPath` if the path is absolute and has an extension. - `Cmd.Start` no longer modifies the `Path` field, allowing safe concurrent use of `String()` and `Start`. ### `os` - `File.WriteTo` method added to support Linux `sendfile(2)` system call. - `LookPath` behavior on Windows improved. - `O_SYNC` now forces direct disk writes on both Unix and Windows. ### `syscall` - **Package no longer deprecated** to avoid false warnings in editors. - **Linux**: - Added `SysProcAttr.PidFD` to obtain a PID file descriptor. - **Windows**: - `O_SYNC` now causes direct disk writes. ### `runtime/pprof` - **Mutex profiles**: - Contention scaled by number of goroutines blocked. - Now includes runtime-internal lock contention. - **CPU profiles on Darwin**: - Include memory map for disassembly in pprof tool. ### `runtime/metrics` - **New histogram metrics**: - `/sched/pauses/stopping/gc:seconds` - `/sched/pauses/stopping/other:seconds` - `/sched/pauses/total/gc:seconds` - `/sched/pauses/total/other:seconds` - **Deprecated**: - `/gc/pauses:seconds` (replaced by `/sched/pauses/total/gc:seconds`) - **`/sync/mutex/wait/total:seconds`**: - Now includes runtime-internal locks. ### `runtime/trace` - **Complete overhaul**: - Uses OS clock (except Windows). - Streamable and partitioned on-the-fly. - Includes full system call durations and OS thread info. - Reduced latency impact. - Can begin/end during GC mark phase. - **Experimental trace reader**: - Available at `golang.org/x/exp/trace`. - Only works with Go 1.22 traces. - **Option to revert to old tracer**: - Build with `GOEXPERIMENT=noexectracer2`. ### `reflect` - `Value.IsZero` behavior updated for consistency with `== 0` comparisons. - `PtrTo` deprecated in favor of `PointerTo`. - `TypeFor[T]()` added for cleaner type reflection. ### `testing/slogtest` - Added `Run` function for running test cases using sub-tests with finer control. ### `slices` - Added `Concat` for concatenating multiple slices. - Slice shrinking functions now zero out extra elements. - `Insert` now panics for invalid indices. --- ## 🔧 Other Notable Changes - **`syscall` package unfrozen**: Still frozen for new features but not deprecated to reduce editor warnings. - **`golang.org/x/sys/unix` and `golang.org/x/sys/windows`** recommended for new code using low-level system calls. - **Improved profiling and tracing capabilities** across the Go runtime. - **New experimental trace reading tools** to help developers analyze execution traces. --- ## 📌 Summary Go 1.22 brings: - **Improved reflection** and type handling. - **Enhanced performance profiling and tracing**. - **Better slice handling and manipulation**. - **Streamlined system-level access** and reduced warnings in editors. - **New APIs and deprecations** for cleaner, more consistent code. This release is a solid step forward, especially for developers working with performance-sensitive code, tracing, and reflection-heavy applications. Let me know if you'd like a comparison with previous versions or a deep dive into specific packages!

Порты

Darwin

В macOS на 64-битной архитектуре x86 (порт darwin/amd64), среда разработки Go теперь по умолчанию генерирует position-independent executables (PIE). НЕ-PIE исполняемые файлы могут быть созданы при использовании флага сборки -buildmode=exe. В 64-битной версии macOS на базе ARM (порт darwin/arm64), среда разработки Go уже по умолчанию генерирует PIE.

Go 1.22 — последний релиз, который будет работать на macOS 10.15 Catalina. Go 1.23 будет требовать macOS 11 Big Sur или более поздней версии.

ARM

Переменная окружения GOARM теперь позволяет выбрать использование программного или аппаратного вещественного числа. Ранее допустимыми значениями GOARM были 5, 6 или 7. Теперь те же самые значения могут быть дополнительно сопровождены ,softfloat или ,hardfloat для выбора реализации вещественной арифметики.

Эта новая опция по умолчанию использует softfloat для версии 5 и hardfloat для версий 6 и 7.

Loong64

Порт loong64 теперь поддерживает передачу аргументов и результатов функций с использованием регистров.

Порт linux/loong64 теперь поддерживает address sanitizer, memory sanitizer, новую модель переопределений линкера и режим сборки plugin.

OpenBSD

Go 1.22 добавляет экспериментальный порт для OpenBSD на 64-битной PowerPC с big-endian порядком байтов (openbsd/ppc64).

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang