Примечания к выпуску 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. Наиболее важные изменения:
- Метод
Read, устаревший вmath/rand, не был передан вmath/rand/v2. (Он остается доступен вmath/rand.) Большинство вызововReadдолжны использоватьcrypto/rand’sReadвместо этого. В противном случае пользовательскийReadможет быть создан с использованием методаUint64. - Глобальный генератор, доступный через функции верхнего уровня, теперь всегда инициализируется случайным образом. Поскольку API гарантирует отсутствие фиксированной последовательности результатов, возможны оптимизации, такие как состояния генератора для каждого потока.
- Интерфейс
Sourceтеперь имеет единственный методUint64; интерфейсаSource64больше нет. - Многие методы теперь используют более быстрые алгоритмы, которые не могли быть внедрены в
math/rand, потому что они изменяли потоки вывода. -
Функции верхнего уровня
Intn,Int31,Int31n,Int63, иInt64nизmath/randвmath/rand/v2имеют более идиоматическое написание:IntN,Int32,Int32N,Int64, иInt64N. Также появились новые функции верхнего уровня и методы:Uint32,Uint32N,Uint64,Uint64N, иUintN. -
Новая дженерик-функция
NаналогичнаInt64NилиUint64N, но работает с любым целочисленным типом. Например, случайная продолжительность от 0 до 5 минут будет:rand.N(5*time.Minute). -
Генератор Mitchell & Reeds LFSR, предоставленный в
math/rand’sSource, был заменён двумя более современными источниками псевдослучайных чисел:ChaCha8иPCG. ChaCha8 — это новый криптографически безопасный генератор случайных чисел, примерно такой же эффективности, как PCG. ChaCha8 используется в функциях верхнего уровня вmath/rand/v2. Начиная с Go 1.22, функции верхнего уровня вmath/rand(если явно не инициализированы) и среда выполнения Go также используют ChaCha8 для генерации случайных чисел.
Порты
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).