Примечания к выпуску Go 1.23
Введение в Go 1.23
Последний выпуск Go, версия 1.23, появился через шесть месяцев после Go 1.22. Большинство изменений касаются реализации инструментария, среды выполнения и библиотек. Как и всегда, выпуск сохраняет обещание совместимости Go 1. Ожидается, что почти все программы на Go продолжат компилироваться и выполняться так же, как и раньше.
Изменения в языке
Предложение «range» в цикле «for-range» теперь принимает функции-итераторы следующих типов
<code>func(func() bool) func(func(K) bool) func(func(K, V) bool) </code>
в качестве выражений для перебора.
Вызов функции-аргумента итератора производит значения для цикла «for-range».
За дополнительной информацией обращайтесь к документации пакета iter,
спецификации языка и статье в блоге Range over Function Types.
Для мотивации см. обсуждение 2022 года “range-over-func”.
Go 1.23 включает предварительную поддержку псевдонимов дженерик-типов.
Сборка инструментария с помощью GOEXPERIMENT=aliastypeparams включает эту функцию внутри пакета.
(Использование псевдонимов дженерик-типов за пределами пакета пока не поддерживается.)
Инструменты
Телеметрия
Начиная с Go 1.23, инструментарий Go может собирать статистику использования и сбоев, которая помогает команде Go понять, как используется инструментарий Go и насколько он эффективен. Мы называем эту статистику Go telemetry.
Go telemetry — это система с выборочной активацией, управляемая командой go telemetry.
По умолчанию программы инструментария собирают статистику в файлы счетчиков, которые можно проверить локально,
но в противном случае не используются (go telemetry local).
Чтобы помочь нам поддерживать работоспособность Go и понимать использование Go,
пожалуйста, рассмотрите возможность включения Go telemetry, выполнив команду
go telemetry on.
В этом режиме анонимные отчеты счетчиков загружаются еженедельно на
telemetry.go.dev,
где они агрегируются в графики и также становятся доступными для загрузки любым участникам или пользователям Go,
желающим проанализировать данные.
См. «Go Telemetry» для получения дополнительных сведений
о системе Go Telemetry.
Команда go
Установка переменной окружения GOROOT_FINAL больше не имеет эффекта
(#62047).
Дистрибутивы, устанавливающие команду go в место, отличное от $GOROOT/bin/go,
должны устанавливать символическую ссылку вместо перемещения или копирования двоичного файла go.
Новый флаг go env -changed заставляет команду выводить только те настройки,
значение которых отличается от значения по умолчанию, которое было бы получено в пустой среде без предыдущих использований флага -w.
Новый флаг go mod tidy -diff заставляет команду не изменять файлы,
а вместо этого выводить необходимые изменения в виде унифицированного diff.
Команда завершается с ненулевым кодом, если требуются обновления.
Команда go list -m -json теперь включает новые поля Sum и GoModSum.
Это аналогично существующему поведению команды go mod download -json.
Новая директива godebug в go.mod и go.work объявляет
настройку GODEBUG, которая применяется к рабочему модулю или рабочей области.
Vet
Подкоманда go vet теперь включает анализатор
stdversion,
который отмечает ссылки на символы, которые слишком новые для версии Go,
действующей в файле, где они используются. (Действующая версия определяется
директивой go в файле go.mod enclosing пакета, а также любыми
//go:build ограничениями
в файле.)
Например, она будет сообщать диагностику при ссылке на функцию
reflect.TypeFor (введена в go1.22) из файла в модуле, чей файл go.mod указывает go 1.21.
Cgo
cmd/cgo поддерживает новую флаг -ldflags для передачи флагов компоновщику C.
Команда go использует его автоматически, избегая ошибок "argument list too long"
при очень большом CGO_LDFLAGS.
Trace
Инструмент trace теперь лучше справляется с частично поврежденными трассировками, пытаясь
восстановить доступные данные трассировки. Эта функциональность особенно полезна при просмотре
трассировки, собранной во время сбоя программы, поскольку данные трассировки, ведущие к сбою,
теперь будут восстанавливаться в большинстве случаев.
Среда выполнения
Трассировка стека, выводимая средой выполнения после необработанного панического состояния или другого фатального ошибки, теперь отступает вторую и последующие строки сообщения об ошибке (например, аргумент функции panic) на один символ табуляции, чтобы можно было однозначно отличить их от трассировки стека первой горутины. См. #64590 для обсуждения.
Компилятор
Накладные расходы времени сборки при использовании Profile Guided Optimization были значительно снижены. Ранее при включении PGO большие сборки могли видеть увеличение времени сборки на 100% и более. В Go 1.23 накладные расходы должны составлять несколько процентов.
Компилятор в Go 1.23 теперь может перекрывать слоты стека локальных переменных, которые доступны в непересекающихся регионах функции, что снижает использование стека для приложений на Go.
Для 386 и amd64 компилятор будет использовать информацию из PGO для выравнивания определенных
горячих блоков в циклах. Это улучшает производительность дополнительно на 1-1.5% за счет
дополнительных 0.1% размера текста и двоичного файла. Реализация доступна только для 386 и amd64,
так как на других платформах она не показала улучшений. Выравнивание горячих блоков можно отключить с помощью
-gcflags=[<packages>=]-d=alignhot=0.
Компоновщик
Компоновщик теперь запрещает использование директивы //go:linkname для ссылки на
внутренние символы стандартной библиотеки (включая среду выполнения), которые не помечены
директивой //go:linkname в своих определениях.
Аналогично, компоновщик запрещает ссылки на такие символы из ассемблерного кода.
Для обратной совместимости, существующие использования //go:linkname, найденные в
большой открытой кодовой базе, остаются поддерживаемыми.
Любые новые ссылки на внутренние символы стандартной библиотеки будут запрещены.
Флаг командной строки компоновщика -checklinkname=0 может быть использован для отключения
этой проверки, в целях отладки и экспериментов.
При сборке динамически связанного ELF-файла (включая PIE-файл), новый флаг -bindnow включает немедленную привязку функций.
Стандартная библиотека
Изменения в таймерах
Go 1.23 вносит два значительных изменения в реализацию
time.Timer и time.Ticker.
Во-первых, Timer и Ticker, на которые больше не ссылается программа,
становятся пригодными для сборки мусора немедленно, даже если методы Stop не были вызваны.
В более ранних версиях Go неостановленные Timer не собиралась до тех пор, пока они не сработали, а неостановленные Ticker вообще не собиралась.
Во-вторых, канал таймера, связанный с Timer или Ticker, теперь является не буферизованным, с вместимостью 0.
Основным эффектом этого изменения является то, что Go теперь гарантирует,
что для любого вызова метода Reset или Stop не будут отправлены или получены устаревшие значения,
подготовленные до этого вызова.
В более ранних версиях Go использовались каналы с буфером в один элемент,
что затрудняло корректное использование методов Reset и Stop.
Видимым эффектом этого изменения является то, что len и cap каналов таймеров теперь возвращают 0 вместо 1,
что может повлиять на программы, которые опрашивают длину, чтобы решить, будет ли успешным получение из канала таймера.
Такой код должен использовать неблокирующий приём вместо этого.
Это новое поведение включается только тогда, когда основная программа Go находится в модуле с go.mod строкой go, использующей Go 1.23.0 или более позднюю версию.
Когда Go 1.23 собирает более старые программы, старое поведение остаётся в силе.
Новое настройка GODEBUG asynctimerchan=1
может быть использована для возврата к асинхронному поведению каналов,
даже если программа указывает Go 1.23.0 или более позднюю версию в своём файле go.mod.
Новый уникальный пакет
Новый пакет unique предоставляет средства для канонизации значений (как "интернирование" или "хэш-консинг").
Любое значение сравнимого типа может быть канонизировано с помощью новой функции Make[T],
которая производит ссылку на каноническую копию значения в виде Handle[T].
Два Handle[T] равны тогда и только тогда, когда значения, использованные для создания этих хендлов, равны,
что позволяет программам дублировать значения и уменьшать их объем в памяти.
Сравнение двух значений Handle[T] эффективно, сводясь к простому сравнению указателей.
Итераторы
Новый пакет iter предоставляет базовые определения для работы с
пользовательскими итераторами.
Пакет slices добавляет несколько функций, работающих с итераторами:
- All возвращает итератор по индексам и значениям среза.
- Values возвращает итератор по элементам среза.
- Backward возвращает итератор, который проходит по срезу в обратном порядке.
- Collect собирает значения из итератора в новый срез.
- AppendSeq добавляет значения из итератора в существующий срез.
- Sorted собирает значения из итератора в новый срез, а затем сортирует срез.
- SortedFunc аналогичен
Sorted, но с функцией сравнения. - SortedStableFunc аналогичен
SortFunc, но использует стабильный алгоритм сортировки. - Chunk возвращает итератор по последовательным подсрезам до n элементов среза.
Пакет maps добавляет несколько функций, работающих с итераторами:
- All возвращает итератор пар ключ-значение из карты.
- Keys возвращает итератор ключей в карте.
- Values возвращает итератор значений в карте.
- Insert добавляет пары ключ-значение из итератора в существующую карту.
- Collect собирает пары ключ-значение из итератора в новую карту и возвращает её.
Новый пакет structs
Новый пакет structs предоставляет типы для полей структур, которые изменяют свойства содержащего их типа структуры, такие как макет памяти.
В этом релизе единственным таким типом является HostLayout, который указывает, что структура с полем этого типа имеет макет, соответствующий ожиданиям хост-платформы. HostLayout следует использовать в типах, которые передаются в, возвращаются из или доступны через указатель, передаваемый в/из API хост-платформы. Без этого маркера порядок макета структуры не гарантируется спецификацией языка, хотя начиная с Go 1.23 макеты хоста и языка совпадают.
Минорные изменения в библиотеке
archive/tar
Если аргумент FileInfoHeader реализует новый интерфейс FileInfoNames, тогда методы интерфейса будут использоваться для установки значений Uname/Gname заголовка файла. Это позволяет приложениям переопределять системно-зависимый поиск Uname/Gname.
crypto/tls
Клиент TLS теперь поддерживает Encrypted Client Hello черновой спецификации. Эта функция может быть включена установкой поля Config.EncryptedClientHelloConfigList в закодированный ECHConfigList для хоста, к которому осуществляется подключение.
Тип QUICConn, используемый реализациями QUIC, включает новые события, сообщающие о состоянии восстановления сессии, и предоставляет способ для слоя QUIC добавлять данные в билеты сессий и записи кэша сессий.
Цифровые наборы шифров 3DES были удалены из списка по умолчанию, используемого, когда Config.CipherSuites равен nil. По умолчанию можно вернуться, добавив tls3des=1 в переменную окружения GODEBUG.
Экспериментальный механизм обмена ключами постквантовой криптографии X25519Kyber768Draft00 теперь включен по умолчанию, когда Config.CurvePreferences равен nil. По умолчанию можно вернуться, добавив tlskyber=0 в переменную окружения GODEBUG. Это может быть полезно при работе с некорректно работающими серверами TLS, которые некорректно обрабатывают большие записи, вызывая таймаут во время рукопожатия (см. TLS post-quantum TL;DR fail).
В Go 1.23 изменено поведение X509KeyPair и LoadX509KeyPair для заполнения поля Certificate.Leaf возвращаемого типа Certificate. Добавлена новая настройка x509keypairleaf в GODEBUG для этого поведения.
crypto/x509
CreateCertificateRequest теперь корректно поддерживает алгоритмы подписи RSA-PSS.
CreateCertificateRequest и CreateRevocationList теперь проверяют сгенерированную подпись с использованием открытого ключа подписывающего лица. Если подпись недействительна, возвращается ошибка. Такое поведение уже было у CreateCertificate начиная с Go 1.16.
Настройка x509sha1 GODEBUG будет удалена в следующем мажорном релизе Go (Go 1.24). Это означает, что пакет crypto/x509 больше не будет поддерживать проверку подписей сертификатов, использующих алгоритмы подписи на основе SHA-1.
Новая функция ParseOID разбирает строку ASN.1 Object Identifier в точечном формате. Тип OID теперь реализует интерфейсы encoding.BinaryMarshaler, encoding.BinaryUnmarshaler, encoding.TextMarshaler, encoding.TextUnmarshaler.
database/sql
Ошибки, возвращаемые реализациями driver.Valuer, теперь оборачиваются для улучшения обработки ошибок во время операций, таких как DB.Query, DB.Exec и DB.QueryRow.
debug/elf
Пакет debug/elf теперь определяет PT_OPENBSD_NOBTCFI. Этот ProgType используется для отключения применения контроля целостности потока управления Branch Tracking (BTCFI) на бинарных файлах OpenBSD.
Теперь определены константы типов символов STT_RELC, STT_SRELC и STT_GNU_IFUNC.
encoding/binary
Новые функции Encode и Decode являются эквивалентами Read и Write, но работают с срезами байтов.
Append позволяет сериализовать несколько данных в один и тот же срез байтов.
go/ast
Новая функция Preorder возвращает удобный итератор по всем узлам синтаксического дерева.
go/types
Тип Func, представляющий символ функции или метода, теперь имеет метод Func.Signature, возвращающий тип функции, который всегда является Signature.
Тип Alias теперь имеет метод Rhs, возвращающий тип справа от объявления: при объявлении type A = B, Rhs для A будет B. (#66559)
Были добавлены методы Alias.Origin, Alias.SetTypeParams, Alias.TypeParams и Alias.TypeArgs. Они необходимы для дженерик-псевдонимов типов.
По умолчанию, пакет go/types теперь генерирует узлы типа Alias для псевдонимов типов. Это поведение можно контролировать с помощью флага GODEBUG gotypesalias. По умолчанию он изменился с 0 в Go 1.22 на 1 в Go 1.23.
math/rand/v2
Была добавлена функция Uint и метод Rand.Uint. Они были случайно опущены в Go 1.22.
Новый метод ChaCha8.Read реализует интерфейс io.Reader.
net
Новый тип KeepAliveConfig позволяет тонко настраивать параметры keep-alive для TCP-соединений через новый метод TCPConn.SetKeepAliveConfig и новые поля KeepAliveConfig для Dialer и ListenConfig.
Тип DNSError теперь оборачивает ошибки, вызванные таймаутами или отменой. Например, errors.Is(someDNSErr, context.DeadlineExceedeed) теперь сообщает, была ли ошибка DNS вызвана таймаутом.
Новая настройка GODEBUG netedns0=0 отключает отправку дополнительных заголовков EDNS0 в DNS-запросах, поскольку они, как сообщается, ломают DNS-сервер на некоторых модемах.
net/http
Cookie теперь сохраняет двойные кавычки, окружающие значение cookie. Новое поле Cookie.Quoted указывает, были ли значения Cookie.Value изначально заключены в кавычки.
Новый метод Request.CookiesNamed извлекает все cookies, соответствующие заданному имени.
Новое поле Cookie.Partitioned идентифицирует cookies с атрибутом Partitioned.
Шаблоны, используемые ServeMux, теперь позволяют одно или несколько пробелов или табуляций после имени метода. Ранее разрешался только один пробел.
Новая функция ParseCookie разбирает значение заголовка Cookie и возвращает все cookies, которые были установлены в нём. Поскольку одно и то же имя cookie может встречаться несколько раз, возвращаемые значения могут содержать более одного значения для данного ключа.
Новая функция ParseSetCookie разбирает значение заголовка Set-Cookie и возвращает cookie. При синтаксической ошибке она возвращает ошибку.
ServeContent, ServeFile и ServeFileFS теперь удаляют заголовки Cache-Control, Content-Encoding, Etag и Last-Modified при обслуживании ошибки. Эти заголовки обычно применяются к неошибочному содержимому, но не к тексту ошибок.
Промежуточное ПО, которое оборачивает ResponseWriter и применяет кодирование на лету, например, Content-Encoding: gzip, больше не будет работать после этого изменения. Предыдущее поведение ServeContent, ServeFile и ServeFileFS может быть восстановлено установкой GODEBUG=httpservecontentkeepheaders=1.
Обратите внимание, что промежуточное ПО, изменяющее размер содержимого, предоставляемого (например, сжимающее его), уже не работает должным образом, когда ServeContent обрабатывает запрос диапазона. Сжатие в режиме реального времени должно использовать заголовок Transfer-Encoding вместо Content-Encoding.
Для входящих запросов, новое поле Request.Pattern содержит шаблон ServeMux (если он есть), который соответствовал запросу. Это поле не устанавливается, когда задан параметр GODEBUG=httpmuxgo121=1.
net/http/httptest
Новый метод NewRequestWithContext создаёт входящий запрос с context.Context.
net/netip
В Go 1.22 и более ранних версиях использование reflect.DeepEqual для сравнения Addr, содержащего IPv4-адрес, с Addr, содержащим IPv4-сопоставленный IPv6-формат этого адреса, неправильно возвращало true, даже если значения Addr были разными при сравнении с помощью == или Addr.Compare. Эта ошибка теперь исправлена, и все три подхода теперь дают одинаковый результат.
os
Функция Stat теперь устанавливает бит ModeSocket для файлов, являющихся сокетами Unix на Windows. Эти файлы идентифицируются по наличию установленного тега повторного анализа (reparse tag) в IO_REPARSE_TAG_AF_UNIX.
В Windows, биты режима, возвращаемые Lstat и Stat для точек повторного анализа, изменились. Точки монтирования больше не имеют установленного бита ModeSymlink, а точки повторного анализа, которые не являются символическими ссылками, сокетами Unix или файлами дедупликации, теперь всегда имеют установленный бит ModeIrregular. Это поведение контролируется параметром winsymlink. Для Go 1.23 значение по умолчанию — winsymlink=1. В предыдущих версиях значение по умолчанию — winsymlink=0.
Функция CopyFS копирует io/fs.FS в локальную файловую систему.
В Windows, Readlink больше не пытается нормализовать тома в буквы дисков, что не всегда было возможно. Это поведение контролируется параметром winreadlinkvolume. Для Go 1.23 значение по умолчанию — winreadlinkvolume=1. В предыдущих версиях значение по умолчанию — winreadlinkvolume=0.
В Linux с поддержкой pidfd (обычно Linux v5.4+), функции и методы, связанные с Process, используют pidfd (вместо PID) внутренне, что устраняет потенциальное неправильное направление запроса, когда PID переиспользуется операционной системой. Поддержка pidfd полностью прозрачна для пользователя, кроме дополнительных дескрипторов файлов процесса.
path/filepath
Новая функция Localize безопасно преобразует путь, разделённый косой чертой, в путь операционной системы.
В Windows, EvalSymlinks больше не разворачивает точки монтирования, что было источником множества несогласованностей и ошибок. Это поведение контролируется параметром winsymlink. Для Go 1.23 значение по умолчанию — winsymlink=1. В предыдущих версиях значение по умолчанию — winsymlink=0.
В Windows, EvalSymlinks больше не пытается нормализовать тома в буквы дисков, что не всегда было возможно. Это поведение управляется параметром winreadlinkvolume. Для Go 1.23 значение по умолчанию равно winreadlinkvolume=1. В предыдущих версиях значение по умолчанию равно winreadlinkvolume=0.
reflect
Новые методы, синонимы методов с тем же именем в Value, добавлены в Type:
Новая функция SliceAt аналогична NewAt, но предназначена для срезов.
Методы Value.Pointer и Value.UnsafePointer теперь поддерживают значения типа String.
Новые методы Value.Seq и Value.Seq2 возвращают последовательности, которые итерируют по значению, как если бы оно использовалось в цикле for/range. Новые методы Type.CanSeq и Type.CanSeq2 сообщают, будет ли вызов Value.Seq и Value.Seq2 успешным без паники.
runtime/debug
Функция SetCrashOutput позволяет пользователю указать альтернативный файл, в который среда выполнения должна записывать отчет о фатальном сбое. Ее можно использовать для создания механизма автоматического отчета обо всех неожиданных сбоях, а не только тех, что происходят в горутинах, явно использующих recover.
runtime/pprof
Максимальная глубина стека для профилей alloc, mutex, block, threadcreate и goroutine была увеличена с 32 до 128 кадров.
runtime/trace
Среда выполнения теперь явно сбрасывает данные трассировки при сбое программы из-за необработанного панического вызова. Это означает, что при активной трассировке в случае сбоя программы будет доступна более полная информация о трассировке.
slices
Функция Repeat возвращает новый срез, который повторяет предоставленный срез заданное количество раз.
sync
Метод Map.Clear удаляет все записи, в результате чего Map становится пустой. Он аналогичен операции clear.
sync/atomic
Новые операторы And и Or применяют побитовое AND или OR к заданному входному значению и возвращают старое значение.
syscall
Пакет syscall теперь определяет WSAENOPROTOOPT в Windows.
Функция GetsockoptInt теперь поддерживается в Windows.
testing/fstest
TestFS теперь возвращает структурированную ошибку, которую можно развернуть
(через метод Unwrap() []error). Это позволяет проверять ошибки
с использованием errors.Is или errors.As.
text/template
Шаблоны теперь поддерживают новое действие "else with", которое уменьшает сложность шаблонов в некоторых случаях использования.
time
Parse и ParseInLocation теперь возвращают ошибку, если смещение часового пояса выходит за пределы допустимого диапазона.
В Windows у Timer, Ticker и функций, которые помещают горутину в спящий режим,
например Sleep, была улучшена точность времени до 0.5 мс вместо 15.6 мс.
unicode/utf16
Функция RuneLen возвращает количество 16-битных слов в
UTF-16 кодировке руны. Если руна не может быть корректно закодирована в UTF-16, функция возвращает -1.
Платформы
Darwin
Как было объявлено в заметках о выпуске Go 1.22, Go 1.23 требует macOS 11 Big Sur или более поздней версии; поддержка предыдущих версий прекращена.
Linux
Go 1.23 — это последний выпуск, который требует ядра Linux версии 2.6.32 или более поздней. Go 1.24 будет требовать ядро Linux версии 3.2 или более поздней.
OpenBSD
Go 1.23 добавляет экспериментальную поддержку OpenBSD на 64-битном RISC-V (GOOS=openbsd, GOARCH=riscv64).
ARM64
Go 1.23 вводит новую переменную окружения GOARM64, которая указывает минимальную целевую версию архитектуры ARM64 во время компиляции. Допустимые значения: v8.{0-9} и v9.{0-5}. После указания версии может следовать опция, указывающая расширения, реализованные целевым оборудованием. Допустимые опции: ,lse и ,crypto.
Переменная окружения GOARM64 по умолчанию равна v8.0.
RISC-V
Go 1.23 вводит новую переменную окружения GORISCV64, которая выбирает профиль пользовательского режима приложения RISC-V, для которого будет осуществляться компиляция. Допустимые значения: rva20u64 и rva22u64.
Переменная окружения GORISCV64 по умолчанию равна rva20u64.
Wasm
Скрипт go_wasip1_wasm_exec в GOROOT/misc/wasm больше не поддерживает версии wasmtime < 14.0.0.