пятница, 17 мая 2024 г.

Релиз Go 1.22

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

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

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

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

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

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

Инструменты

Команда go

Команды в рабочих областях теперь могут использовать каталог vendor, содержащий зависимости рабочей области. Каталог создается go work vendor и используется командами сборки, когда для флага -mod установлено значение 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

? mymod/mypack [no test files]

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

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

Trace

Веб-интерфейс инструмента трассировки был слегка обновлен в рамках работы по поддержке нового средства трассировки, что позволило решить несколько проблем и улучшить читаемость различных подстраниц. Веб-интерфейс теперь поддерживает изучение трассировок в поточно-ориентированном представлении. Средство просмотра трассировки теперь также отображает полную продолжительность всех системных вызовов.

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

Go Vet

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

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

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

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

Новые предупреждения об отсрочке (defer) time.Since.

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

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
}()

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

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

Среда времени исполнения (runtime)

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

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

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

Компилятор

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

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

Go 1.22 также включает предварительную версию расширенной реализации фазы встраивания компилятора, которая использует эвристику для повышения встраиваемости на местах вызовов, которые считаются "важными" (например, в циклах), и препятствует встраиванию на местах вызовов, которые считаются "неважными" (например, на пути паники). Сборка с использованием GOEXPERIMENT=newinliner позволяет использовать новую эвристику места вызова.

Линкер

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

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

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

Бутстрап

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

Основная библиотека

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

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

  • Метод Read, устаревший в math/rand, не был перенесен в math/rand/v2. (Он остается доступным в math/rand.) Подавляющее большинство вызовов Read должны использовать вместо этого Read crypto/rand. В противном случае можно создать пользовательский 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, Uint и UintN.
  • Новая универсальная функция N похожа на Int64N или Uint64N, но работает для любого целочисленного типа. Например, случайная длительность от 0 до 5 минут равна rand.N(5*time.Minute).
  • Генератор LFSR Mitchell & Reeds, предоставленный math/rand Source, был заменен двумя более современными источниками псевдослучайного генератора: ChaCha8 и PCG. ChaCha8 — это новый, криптостойкий генератор случайных чисел, по эффективности примерно аналогичный PCG. ChaCha8 — это алгоритм, используемый для функций верхнего уровня в math/rand/v2. Начиная с Go 1.22, функции верхнего уровня math/rand (если они не заданы явно) и среда выполнения Go также используют ChaCha8 для случайности.

Планируется включить инструмент миграции API в будущую версию, скорее всего, в Go 1.23.

Новый пакет go/version

Новый пакет go/version реализует функции для проверки и сравнения строк версии Go.

Улучшенные шаблоны маршрутизации

HTTP-маршрутизация в стандартной библиотеке стала более выразительной. Шаблоны, используемые net/http.ServeMux, были улучшены и теперь принимают методы и подстановочные знаки.

Регистрация обработчика с помощью метода, например "POST/items/create", ограничивает вызовы обработчика запросами с данным методом. Шаблон с методом имеет приоритет над совпадающим шаблоном без него. В частном случае регистрация обработчика с помощью "GET" также регистрирует его с помощью "HEAD".

Подстановочные знаки в шаблонах, например /items/{id}, соответствуют сегментам URL-пути. Доступ к фактическому значению сегмента можно получить, вызвав метод Request.PathValue. Подстановочный знак, оканчивающийся на "...", например /files/{path...}, должен находиться в конце шаблона и соответствовать всем остальным сегментам.

Шаблон, оканчивающийся на "/", как всегда, соответствует всем путям, в которых он есть в качестве префикса. Чтобы точно соответствовать шаблону, включая косую черту, завершите его {$}, как в /exact/match/{$}.

Если два шаблона перекрываются в запросах, которым они соответствуют, приоритет имеет более конкретный шаблон. Если ни один из них не является более конкретным, шаблоны конфликтуют. Это правило обобщает исходные правила приоритета и сохраняет то свойство, что порядок регистрации шаблонов не имеет значения.

Это изменение нарушает обратную совместимость в некоторых аспектах, некоторые из которых очевидны — шаблоны с "{" и "}" ведут себя по-другому, а некоторые — в меньшей степени — улучшена обработка экранированных путей. Изменение контролируется полем GODEBUG с именем httpmuxgo121. Установите httpmuxgo121=1, чтобы восстановить старое поведение.

Небольшие изменения в библиотеке

Как всегда, в библиотеку внесены различные незначительные изменения и обновления, сделанные с учетом обеспечения совместимости с Go 1. Существуют также различные улучшения производительности, которые здесь не перечислены.

archive/tar

Новый метод Writer.AddFS добавляет в архив все файлы из fs.FS.

archive/zip

Новый метод Writer.AddFS добавляет в архив все файлы из fs.FS.

bufio

Когда SplitFunc возвращает ErrFinalToken с нулевым токеном, Scanner немедленно останавливается. Раньше перед остановкой он сообщал об окончательном пустом токене, что обычно было нежелательно. Вызывающие, которые хотят сообщить об окончательном пустом токене, могут сделать это, вернув []byte{}, а не nil.

cmp

Новая функция Or возвращает первое значение в последовательности, которое не является нулевым значением.

crypto/tls

ConnectionState.ExportKeyingMaterial теперь будет возвращать ошибку, если не используется TLS 1.3 или расширение Extended_master_secret не поддерживается как сервером, так и клиентом. crypto/tls поддерживает это расширение начиная с Go 1.20. Это можно отключить с помощью параметра tlsunsafeekm=1 GODEBUG.

По умолчанию минимальной версией, предлагаемой серверами crypto/tls, теперь является TLS 1.2, если она не указана в config.MinimumVersion, что соответствует поведению клиентов crypto/tls. Это изменение можно отменить с помощью параметра tls10server=1 GODEBUG.

По умолчанию наборы шифров без поддержки ECDHE больше не предлагаются ни клиентами, ни серверами во время рукопожатий до TLS 1.3. Это изменение можно отменить с помощью настройки tlsrsakex=1 GODEBUG.

crypto/x509

Новый метод CertPool.AddCertWithConstraint можно использовать для добавления настраиваемых ограничений к корневым сертификатам, которые будут применяться во время построения цепочки.

В Android корневые сертификаты теперь будут загружаться из /data/misc/keychain/certs-added, а также из /system/etc/security/cacerts.

Новый тип OID поддерживает идентификаторы объектов ASN.1 с отдельными компонентами длиной более 31 бита. Новое поле, использующее этот тип, Policies, добавляется в структуру сертификата и теперь заполняется во время анализа. Любые OID, которые невозможно представить с помощью asn1.ObjectIdentifier, появятся в политиках, но не в старом поле PolicyIdentifiers. При вызове CreateCertificate поле Policies игнорируется, а политики берутся из поля PolicyIdentifiers. Использование параметра x509usepolicies=1 GODEBUG инвертирует это, заполняя политики сертификатов из поля Policies и игнорируя поле PolicyIdentifiers. Возможно изменение значения по умолчанию для x509usepolicies в Go 1.23, которое сделает Policies полем по умолчанию для маршалинга.

database/sql

Новый тип Null[T] предоставляет возможность сканирования столбцов, допускающих значение NULL, на предмет любых типов столбцов.

debug/elf

Константа R_MIPS_PC32 определена для использования с системами MIPS64.

Дополнительные константы R_LARCH_* определены для использования с системами LoongArch.

encoding

Новые методы AppendEncode и AppendDecode, добавленные к каждому из типов кодирования в пакетах  encoding/base32, encoding/base64 и encoding/hex, упрощают кодирование и декодирование из и в байтовые срезы, заботясь об управлении буфером байтовых срезов.

Методы base32.Encoding.WithPadding и base64.Encoding.WithPadding теперь вызывают панику, если аргумент заполнения имеет отрицательное значение, отличное от NoPadding.

encoding/json

Функции маршалинга и кодирования теперь экранируют символы '\b' и '\f' как \b и \f вместо \u0008 и \u000c.

go/ast

Следующие объявления, связанные с разрешением синтаксических идентификаторов, теперь устарели: Ident.Obj, Object, Scope, File.Scope, File.Unresolved, Importer, Package, NewPackage. В общем, идентификаторы не могут быть точно определены без информации о типе. Рассмотрим, например, идентификатор K в T{K: ""}: это может быть имя локальной переменной, если T является типом карты, или именем поля, если T является типом структуры. Новые программы должны использовать пакет go/types для разрешения идентификаторов.

Новая функция ast.Unparen удаляет из выражения все закрывающие круглые скобки.

go/types

Новый тип Alias представляет псевдонимы типов. Раньше псевдонимы типов не представлялись явно, поэтому ссылка на псевдоним типа была эквивалентна указанию псевдонима типа, и имя псевдонима терялось. Новое представление сохраняет промежуточный псевдоним. Это позволяет улучшить отчеты об ошибках (можно сообщить имя псевдонима типа) и позволяет лучше обрабатывать объявления циклических типов, включающие псевдонимы типов. В будущем выпуске типы псевдонимов также будут содержать информацию о параметрах типа. Новая функция Unalias возвращает фактический тип, обозначенный типом Alias (или любым другим типом, если на то пошло).

Поскольку типы псевдонимов могут нарушить работу существующих переключателей типов, которые не умеют их проверять, эта функциональность контролируется полем GODEBUG с именем gotypesalias. Если gotypesalias=0, все работает как прежде, и типы псевдонимов никогда не создаются. Если gotypesalias=1, создаются типы псевдонимов, и клиенты должны их ожидать. По умолчанию используется gotypesalias=0. В будущем релизе значение по умолчанию будет изменено на gotypesalias=1. Клиентам go/types настоятельно рекомендуется как можно скорее скорректировать свой код для работы с gotypesalias=1, чтобы устранить проблемы на раннем этапе.

Структура Info теперь экспортирует карту FileVersions, которая предоставляет информацию о версии Go для каждого файла.

Новый вспомогательный метод PkgNameOf возвращает имя локального пакета для данного объявления импорта.

Реализация SizesFor была скорректирована для вычисления тех же размеров типов, что и компилятор, когда аргументом компилятора SizesFor является "gc". Реализация Sizes по умолчанию, используемая средством проверки типов, теперь имеет вид Types.SizesFor("gc", "amd64").

Начальная позиция (Pos) блока лексического окружения (Scope), представляющего тело функции, изменилась: раньше она начиналась с открывающей фигурной скобки тела функции, но теперь начинается с функционального токена функции.

html/template

Литералы шаблонов Javascript теперь могут содержать действия шаблона Go, а анализ шаблона, содержащего такие действия, больше не будет возвращать ErrJSTemplate. Аналогично, параметр jstmpllitinterp в GODEBUG больше не имеет никакого эффекта.

io

Новый метод SectionReader.Outer возвращает ReaderAt, смещение и размер, переданные в NewSectionReader.

log/slog

Новая функция SetLogLoggerLevel контролирует уровень моста между пакетами `slog` и `log`. Он устанавливает минимальный уровень для вызовов функций ведения журнала `slog` верхнего уровня, а также устанавливает уровень для вызовов `log.Logger`, которые проходят через `slog`.

math/big

Новый метод Rat.FloatPrec вычисляет количество дробных десятичных цифр, необходимых для точного представления рационального числа в виде числа с плавающей запятой, а также определяет, возможно ли вообще точное десятичное представление.

net

Когда io.Copy копирует из TCPConn в UnixConn, он теперь будет использовать системный вызов Linux splice(2), если это возможно, используя новый метод TCPConn.WriteTo.

DNS-резольвер Go, используемый при сборке с "-tags=netgo", теперь ищет соответствующее имя в файле хостов Windows, расположенном по адресу %SystemRoot%\System32\drivers\etc\hosts, перед выполнением DNS-запроса.

net/http

Новые функции ServeFileFS, FileServerFS и NewFileTransportFS являются версиями существующих ServeFile, FileServer и NewFileTransport, работающих на fs.FS.

HTTP-сервер и клиент теперь отклоняют запросы и ответы, содержащие недопустимый пустой заголовок Content-Length. Предыдущее поведение можно восстановить, установив поле GODEBUG httplaxcontentlength=1.

Новый метод Request.PathValue возвращает значения подстановочных знаков пути из запроса, а новый метод Request.SetPathValue устанавливает значения подстановочных знаков пути в запросе.

net/http/cgi

При выполнении процесса CGI переменной PATH_INFO теперь всегда присваивается пустая строка или значение, начинающееся с символа /, как того требует RFC 3875. Ранее для некоторых комбинаций Handler.Root и URL-адреса запроса было возможно нарушить это требование.

net/netip

Новый метод AddrPort.Compare сравнивает два AddrPort.

os

В Windows функция Stat теперь следует за всеми точками повторной обработки, которые ссылаются на другой именованный объект в системе. Раньше он следовал только за точками повторной обработки IO_REPARSE_TAG_SYMLINK и IO_REPARSE_TAG_MOUNT_POINT.

В Windows передача O_SYNC в OpenFile теперь приводит к тому, что операции записи передаются непосредственно на диск, что эквивалентно O_SYNC на платформах Unix.

В Windows функции ReadDir, File.ReadDir, File.Readdir и File.Readdirnames теперь считывают записи каталога в пакетном режиме, чтобы сократить количество системных вызовов, повышая производительность до 30%.

Когда io.Copy копирует из файла в net.UnixConn, он теперь будет использовать системный вызов Linux sendfile(2), если это возможно, используя новый метод File.WriteTo.

os/exec

В Windows LookPath теперь игнорирует пустые записи в %PATH% и возвращает ErrNotFound (вместо ErrNotExist), если не найдено расширение исполняемого файла для разрешения однозначного имени.

В Windows Command и Cmd.Start больше не вызывают LookPath, если путь к исполняемому файлу уже является абсолютным и имеет расширение исполняемого файла. Кроме того, Cmd.Start больше не записывает разрешенное расширение обратно в поле Path, поэтому теперь можно безопасно вызывать метод String одновременно с вызовом Start.

reflect

Метод Value.IsZero теперь возвращает true для числа с плавающей запятой или комплексного отрицательного нуля, а также возвращает true для значения структуры, если пустое поле (поле с именем _) каким-то образом имеет ненулевое значение. Эти изменения делают IsZero совместимым со сравнением значения с нулем с помощью оператора языка ==.

Функция PtrTo устарела в пользу PointerTo.

Новая функция TypeFor возвращает Type, который представляет аргумент типа T. Раньше, чтобы получить значение Reflect.Type для типа, нужно было использовать Reflect.TypeOf((*T)(nil)).Elem(). Теперь это можно записать как reflect.TypeFor[T]().

runtime/metrics

Четыре новых показателя гистограммы /sched/pauses/stopping/gc:seconds, /sched/pauses/stopping/other:seconds, /sched/pauses/total/gc:seconds и /sched/pauses/total/other:seconds предоставляют дополнительные подробности о паузах, связанных с остановкой мира. Метрики "остановки" сообщают о времени, прошедшем от принятия решения об остановке мира до остановки всех горутин. "Общие" показатели сообщают о времени, прошедшем от принятия решения остановить мир до его повторного запуска.

Метрика /gc/pauses:seconds устарела, поскольку она эквивалентна новой метрике /sched/pauses/total/gc:seconds.

/sync/mutex/wait/total:seconds теперь включают в себя конфликты по внутренним блокировкам времени выполнения в дополнение к sync.Mutex и sync.RWMutex.

runtime/pprof

Профили мьютексов теперь масштабируют конкуренцию по количеству горутин, заблокированных во мьютексе. Это обеспечивает более точное представление о степени, в которой мьютекс является узким местом в программе Go. Например, если 100 горутин заблокированы мьютексом на 10 миллисекунд, профиль мьютекса теперь будет записывать задержку в 1 секунду вместо задержки в 10 миллисекунд.

Профили мьютексов теперь также включают конкуренцию за внутренние блокировки во время выполнения в дополнение к sync.Mutex и sync.RWMutex. Конфликт по внутренним блокировкам во время выполнения всегда сообщается во время runtime._LostContendedRuntimeLock. В будущих версиях в этих случаях будут добавлены полные трассировки стека.

Профили ЦП на платформах Darwin теперь содержат карту памяти процесса, что позволяет просматривать дизассемблирование в инструменте pprof.

runtime/trace

В этом выпуске трассировщик выполнения был полностью переработан, что решило несколько давних проблем и открыло путь для новых вариантов использования трассировки выполнения.

Трассировки выполнения теперь используют часы операционной системы на большинстве платформ (за исключением Windows), поэтому их можно сопоставить со трассировками, создаваемыми компонентами более низкого уровня. Трассировки выполнения больше не зависят от надежности часов платформы для создания правильной трассировки. Трассировки выполнения теперь регулярно секционируются на лету и, как следствие, могут обрабатываться в потоковом режиме. Трассировки выполнения теперь содержат полную длительность всех системных вызовов. Трассировки выполнения теперь содержат информацию о потоках операционной системы, в которых выполнялись горутины. Влияние задержки при запуске и остановке трассировки выполнения было значительно уменьшено. Трассировки выполнения теперь могут начинаться или заканчиваться на этапе метки сборки мусора.

Чтобы разработчики Go могли воспользоваться этими улучшениями, по адресу golang.org/x/exp/trace доступен экспериментальный пакет для чтения трассировки. Обратите внимание, что этот пакет работает только с трассировками, созданными программами, созданными на данный момент с помощью Go 1.22.

Если у вас возникнут какие-либо проблемы с новой реализацией трассировщика выполнения, вы можете вернуться к старой реализации, создав программу Go с GOEXPERIMENT=noexectracer2. Если да, сообщите о проблеме, иначе эта опция будет удалена в будущем релизе.

slices

Новая функция Concat объединяет несколько срезов.

Функции, уменьшающие размер среза (Delete, DeleteFunc, Compact, CompactFunc и Replace), теперь обнуляют элементы между новой длиной и старой длиной.

Команда Insert теперь всегда вызывает панику, если аргумент i выходит за пределы допустимого диапазона. Раньше в этой ситуации не паниковало, если не было элементов для вставки.

syscall

Пакет системных вызовов был заморожен начиная с Go 1.4 и помечен как устаревший в Go 1.11, из-за чего многие редакторы предупреждают о любом использовании пакета. Однако для некоторых неустаревших функций требуется использование пакета syscall, например поля os/exec.Cmd.SysProcAttr. Чтобы избежать ненужных жалоб на такой код, пакет syscall больше не помечается как устаревший. Пакет остается замороженным для большинства новых функций, и в новом коде по-прежнему рекомендуется использовать golang.org/x/sys/unix или golang.org/x/sys/windows, где это возможно.

В Linux новое поле SysProcAttr.PidFD позволяет получить PID FD при запуске дочернего процесса через StartProcess или os/exec.

В Windows передача O_SYNC в Open теперь приводит к тому, что операции записи передаются непосредственно на диск, что эквивалентно O_SYNC на платформах Unix.

testing/slogtest

Новая функция Run использует подтесты для запуска тестовых случаев, обеспечивая более детальный контроль.

Порты

Darwin

В macOS на 64-битной архитектуре x86 (порт darwin/amd64) набор инструментов Go теперь по умолчанию генерирует позиционно-независимые исполняемые файлы (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 для выбора реализации с плавающей запятой.

Эта новая опция по умолчанию имеет мягкое плавание для версии 5 и жесткое плавание для версий 6 и 7.

Loong64

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

Порт linux/loong64 теперь поддерживает очистку адресов, очистку памяти, перемещение компоновщика нового стиля и режим сборки плагинов.

OpenBSD

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


Читайте также:


вторник, 29 августа 2023 г.

Релиз Go 1.21

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

В Go 1.21 внесено небольшое изменение в нумерацию релизов. В прошлом использовали Go 1.N для обозначения как общей языковой версии Go, так и семейства релизов, а также первого релиза в этом семействе. Начиная с версии Go 1.21, первый релиз теперь называется Go 1.N.0. В этот раз выпускается как язык Go 1.21, так и его первоначальная реализация, версию Go 1.21.0. Эти примечания относятся к "Go 1.21"; такие инструменты, как go version, будут сообщать "go1.21.0" (пока вы не обновитесь до версии Go 1.21.1).

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

Go 1.21 добавляет в язык три новых встроенных модуля.

  • Новые функции min и max вычисляют наименьшее (или наибольшее для max) значение фиксированного числа заданных аргументов.
  • Новая функция clear удаляет все элементы с карты или обнуляет все элементы среза.

Порядок инициализации пакетов теперь указан более точно. Новый алгоритм таков:

  • Отсортируйте все пакеты по пути импорта.
  • Повторяйте, пока список пакетов не станет пустым:
    • Найдите в списке первый пакет, для которого все импорты уже инициализированы.
    • Инициализируйте этот пакет и удалите его из списка.

Это может изменить поведение некоторых программ, которые полагаются на определенный порядок инициализации, не выраженный явным импортом. Поведение таких программ не было четко определено спецификацией в прошлых релизах. Новое правило дает однозначное определение.

Внесено множество улучшений, повышающих мощность и точность вывода типов.

  • Функция (возможно, частично созданная универсальная) теперь может быть вызвана с аргументами, которые сами являются (возможно, частично созданными) универсальными функциями. Компилятор попытается вывести отсутствующие аргументы типа вызываемого объекта (как и раньше) и для каждого аргумента, который является универсальной функцией, экземпляр которой не полностью создан, его отсутствующие аргументы типа (новые). Типичными вариантами использования являются вызовы универсальных функций, работающих с контейнерами (например, slices.IndexFunc), где аргумент функции также может быть универсальным, а аргумент типа вызываемой функции и ее аргументы выводятся из типа контейнера. В более общем смысле универсальную функцию теперь можно использовать без явного создания экземпляра, когда она присваивается переменной или возвращается как значение результата, если аргументы типа можно вывести из присваивания.
  • Вывод типа теперь также учитывает методы, когда значение присваивается интерфейсу: аргументы типа для параметров типа, используемых в сигнатурах методов, могут быть выведены из соответствующих типов параметров соответствующих методов.
  • Точно так же, поскольку аргумент типа должен реализовывать все методы соответствующего ограничения, методы аргумента типа и ограничения совпадают, что может привести к выводу дополнительных аргументов типа.
  • Если несколько нетипизированных постоянных аргументов разных типов (таких как нетипизированное целое число и нетипизированная константа с плавающей запятой) передаются параметрам с одним и тем же (не указанным иным образом) типом параметра типа вместо ошибки, теперь вывод типа определяет тип, используя тот же подход, что и у оператора с нетипизированными постоянными операндами. Это изменение приводит типы, выведенные из нетипизированных константных аргументов, в соответствие с типами константных выражений.
  • Вывод типа теперь является точным при сопоставлении соответствующих типов в присваиваниях: типы компонентов (такие как элементы срезов или типы параметров в сигнатурах функций) должны быть идентичными (с учетом подходящих аргументов типа) для сопоставления, иначе вывод завершится ошибкой. Это изменение создает более точные сообщения об ошибках: если в прошлом вывод типа мог завершиться неправильно и привести к недопустимому присвоению, теперь компилятор сообщает об ошибке вывода, если два типа не могут совпасть.

В более общем плане описание вывода типов в спецификации языка было уточнено. Вместе все эти изменения делают вывод типов более мощным, а ошибки вывода менее неожиданными.

Go 1.21 включает в себя предварительную версию изменения языка, которое рассматривается для будущей версии Go: создание переменных цикла for для каждой итерации, а не для каждого цикла, чтобы избежать случайного совместного использования ошибок.

Go 1.21 теперь определяет, что если горутина находится в состоянии паники, а функция recovery была вызвана непосредственно отложенной функцией, возвращаемое значение recovery гарантированно не равно нулю. Чтобы гарантировать это, вызов panic со значением интерфейса nil (или нетипизированным nil) вызывает панику во время выполнения типа *runtime.PanicNilError.

Для поддержки программ, написанных для более старых версий Go, nil panic можно повторно включить, установив GODEBUG=panicnil=1. Этот параметр включается автоматически при компиляции программы, основной пакет которой находится в модуле, объявляющем go 1.20 или более ранней версии.

Инструменты

Go 1.21 добавляет улучшенную поддержку обратной и прямой совместимости в цепочке инструментов Go.

Чтобы улучшить обратную совместимость, Go 1.21 формализует использование Go переменной среды GODEBUG для управления поведением по умолчанию для изменений, которые не являются критическими в соответствии с политикой совместимости, но, тем не менее, могут привести к нарушению работы существующих программ. (Например, программы, зависящие от ошибочного поведения, могут сломаться, когда ошибка будет исправлена, но исправления ошибок не считаются критическими изменениями.) Когда Go должен внести такое изменение поведения, теперь он выбирает между старым и новым поведением на основе go в файле go.work рабочей области или в файле go.mod основного модуля. При обновлении до новой цепочки инструментов Go, но с сохранением исходной (старой) версии Go для строки go сохраняется поведение старой цепочки инструментов. Благодаря такой поддержке совместимости последняя цепочка инструментов Go всегда должна быть лучшей и наиболее безопасной реализацией старой версии Go.

Для улучшения совместимости Go 1.21 теперь считывает строку go в файле go.work или go.mod как строгое минимальное требование: go 1.21.0 означает, что рабочее пространство или модуль нельзя использовать с Go 1.20 или Go 1.21rc1. Это позволяет проектам, которые зависят от исправлений, сделанных в более поздних версиях Go, гарантировать, что они не используются с более ранними версиями. Это также дает более качественные отчеты об ошибках для проектов, использующих новые функции Go: когда проблема заключается в том, что требуется более новая версия Go, об этой проблеме сообщается четко, вместо того, чтобы пытаться построить код и печатать ошибки о неразрешенных импортах или синтаксических ошибках.

Чтобы упростить управление этими новыми более строгими требованиями к версии, команда go теперь может вызывать не только цепочку инструментов, входящую в ее собственный релиз, но и другие версии цепочки инструментов Go, найденные в PATH или загруженные по запросу. Если строка go.mod или go.work объявляет минимальные требования к более новой версии Go, команда go автоматически найдет и запустит эту версию. Новая директива цепочки инструментов устанавливает рекомендуемый минимальный набор инструментов для использования, который может быть новее, чем строгий минимум.

Команда go

Флаг сборки -pgo теперь по умолчанию имеет значение -pgo=auto, а ограничение на указание одного основного пакета в командной строке теперь снято. Если файл с именем default.pgo присутствует в каталоге основного пакета, команда go будет использовать его, чтобы включить оптимизацию на основе профиля для сборки соответствующей программы.

Флаг -C dir теперь должен быть первым флагом в командной строке при использовании.

Новая опция go test -fullpath печатает полные пути в сообщениях журнала тестирования, а не только базовые имена.

Флаг go test -c теперь поддерживает запись тестовых двоичных файлов для нескольких пакетов, каждый в pkg.test, где pkg — это имя пакета. Будет ошибкой, если более одного компилируемого тестового пакета имеют заданное имя пакета.

Флаг go test -o теперь принимает аргумент каталога, и в этом случае тестовые двоичные файлы записываются в этот каталог, а не в текущий каталог.

Cgo

В файлах, которые импортируют "C", набор инструментов Go теперь правильно сообщает об ошибках при попытках объявить методы Go для типов C.

Среда времени исполнения (Runtime)

При печати очень глубоких стеков runtime теперь печатает первые 50 (самые внутренние) фреймы, а затем нижние 50 (самые внешние) фреймы, а не просто печатает первые 100 фреймов. Это облегчает понимание того, как запускаются глубоко рекурсивные стеки, и особенно полезно для отладки переполнения стека.

На платформах Linux, которые поддерживают прозрачные огромные страницы (transparent huge pages), среда выполнения Go теперь более явно определяет, какие части кучи могут быть поддержаны огромными страницами. Это приводит к лучшему использованию памяти: для небольших куч должно использоваться меньше памяти (до 50 % в патологических случаях), тогда как для больших куч должно использоваться меньше испорченных огромных страниц для плотных частей кучи, что улучшает использование ЦП и задержку до 1%.

В результате внутренней настройки сборки мусора во время выполнения приложения могут сократить задержку хвоста приложения на 40% и небольшое снижение использования памяти. В некоторых приложениях также может наблюдаться небольшая потеря пропускной способности. Уменьшение использования памяти должно быть пропорционально потере пропускной способности, чтобы компромисс между пропускной способностью и памятью предыдущей версии можно было восстановить (с небольшим изменением задержки) путем небольшого увеличения GOGC и/или GOMEMLIMIT.

Вызовы из C в Go в потоках, созданных в C, требуют некоторой настройки для подготовки к выполнению Go. На платформах Unix эта настройка теперь сохраняется при нескольких вызовах из одного потока. Это значительно снижает накладные расходы на последующие вызовы C в Go с ~1–3 микросекунд на вызов до ~100–200 наносекунд на вызов.

Компилятор

Оптимизация на основе профиля (PGO, Profile-guide optimization), добавленная в качестве предварительной версии в Go 1.20, теперь готова для общего использования. PGO обеспечивает дополнительную оптимизацию кода, который определяется как "горячий" в соответствии с профилями производственных рабочих нагрузок. Как упоминалось в разделе команд Go, PGO включен по умолчанию для двоичных файлов, которые содержат профиль default.pgo в основном каталоге пакета. Улучшение производительности варьируется в зависимости от поведения приложения: в большинстве программ из репрезентативного набора программ Go наблюдается улучшение от 2 до 7% от включения PGO.

Сборки PGO теперь могут девиртуализировать вызовы некоторых методов интерфейса, добавляя конкретный вызов к наиболее распространенному вызываемому объекту. Это обеспечивает дальнейшую оптимизацию, например, встраивание вызываемого объекта.

Go 1.21 повышает скорость сборки до 6%, во многом благодаря сборке самого компилятора с помощью PGO.

Ассемблер

В amd64 безрамочные функции сборки nosplit больше не помечаются автоматически как NOFRAME. Вместо этого при желании атрибут NOFRAME должен быть явно указан, что уже происходит в других архитектурах, поддерживающих указатели фреймов. Благодаря этому среда выполнения теперь поддерживает указатели фреймов для переходов стека.

Улучшен верификатор, проверяющий неправильное использование R15 при динамической компоновке на amd64.

Компоновщик (Linker)

В windows/amd64 компоновщик (с помощью компилятора) теперь по умолчанию выдает данные размотки SEH, что улучшает интеграцию приложений Go с отладчиками Windows и другими инструментами.

В Go 1.21 компоновщик (с помощью компилятора) теперь способен удалять неработающие (не имеющие ссылок) глобальные переменные карты, если количество записей в инициализаторе переменных достаточно велико и если выражения инициализатора не имеют побочных эффектов.

Основная библиотека

Новый пакет log/slog

Новый пакет log/slog обеспечивает структурированное ведение журналов по уровням. Структурированное ведение журналов генерирует пары "ключ-значение", что обеспечивает быструю и точную обработку больших объемов данных журнала. Пакет поддерживает интеграцию с популярными инструментами и сервисами анализа журналов.

Новый пакет testing/slogtest

Новый пакет testing/slogtest может помочь проверить реализации slog.Handler.

Новый пакет slices

Новый пакет slices предоставляет множество общих операций над срезами, используя общие функции, которые работают со срезами любого типа элементов.

Новый пакет maps

Новый пакет maps предоставляет несколько общих операций с картами, используя общие функции, которые работают с картами любого типа ключа или элемента.

Новый пакет cmp

Новый пакет cmp определяет ограничение типа Ordered и две новые универсальные функции Less и Compare, полезные для упорядоченных типов.

Небольшие изменения в библиотеке

Как всегда, в библиотеку внесены различные незначительные изменения и обновления, сделанные с учетом обеспечения совместимости с Go 1. Существуют также различные улучшения производительности, которые здесь не перечислены.

archive/tar

Реализация интерфейса io/fs.FileInfo, возвращаемого Header.FileInfo, теперь реализует метод String, который вызывает io/fs.FormatFileInfo.

archive/zip

Реализация интерфейса io/fs.FileInfo, возвращаемого FileHeader.FileInfo, теперь реализует метод String, который вызывает io/fs.FormatFileInfo.

Реализация интерфейса io/fs.DirEntry, возвращаемого методом io/fs.ReadDirFile.ReadDir io/fs.File, возвращаемого Reader.Open, теперь реализует метод String, который вызывает io/fs.FormatDirEntry.

bytes

Тип Buffer имеет два новых метода: Available и AvailableBuffer. Их можно использовать вместе с методом Write для добавления непосредственно в буфер.

context

Новая функция WithoutCancel возвращает копию контекста, которая не отменяется при отмене исходного контекста.

Новые функции WithDeadlineCause и WithTimeoutCause позволяют установить причину отмены контекста по истечении крайнего срока или таймера. Причину можно выяснить с помощью функции Cause.

Новая функция AfterFunc регистрирует функцию, которая будет запускаться после отмены контекста.

Оптимизация означает, что результаты вызова Background и TODO и преобразования их в общий тип можно считать равными. В предыдущих релизах они всегда были разными. Сравнение значений контекста на предмет равенства никогда не было четко определено, поэтому это не считается несовместимым изменением.

crypto/ecdsa

PublicKey.Equal и PrivateKey.Equal теперь выполняются за постоянное время.

crypto/elliptic

Все методы Curve, а также методы GenerateKey, Marshal и Unmarshal устарели. Для операций ECDH вместо этого следует использовать новый пакет crypto/ecdh. Для операций более низкого уровня используйте сторонние модули, такие как filippo.io/nistec.

crypto/rand

Пакет crypto/rand теперь использует системный вызов getrandom в NetBSD 10.0 и более поздних версиях.

crypto/rsa

Производительность частных операций RSA (расшифровка и подпись) теперь лучше, чем в Go 1.19 для GOARCH=amd64 и GOARCH=arm64. Производительность снижалась в Go 1.20.

Из-за добавления частных полей в PrecomputedValues PrivateKey.Precompute необходимо вызывать для оптимальной производительности даже при десериализации (например, из JSON) предварительно вычисленного закрытого ключа.

PublicKey.Equal и PrivateKey.Equal теперь выполняются за постоянное время.

Функция GenerateMultiPrimeKey и поле PrecomputedValues.CRTValues устарели. PrecomputedValues.CRTValues по-прежнему будет заполняться при вызове PrivateKey.Precompute, но значения не будут использоваться во время операций расшифровки.

crypto/sha256

Операции SHA-224 и SHA-256 теперь используют собственные инструкции, если они доступны при GOARCH=amd64, что обеспечивает повышение производительности примерно в 3–4 раза.

crypto/tls

Серверы теперь пропускают проверку клиентских сертификатов (в том числе отсутствие запуска Config.VerifyPeerCertificate) для возобновленных соединений, помимо проверки срока действия. Это увеличивает размер билетов сеанса, когда используются клиентские сертификаты. Клиенты уже пропускали проверку при возобновлении, но теперь проверяйте время истечения срока действия, даже если установлен Config.InsecureSkipVerify.

Приложения теперь могут контролировать содержимое билетов сеанса.

  • Новый тип SessionState описывает возобновляемый сеанс.
  • Метод SessionState.Bytes и функция ParseSessionState сериализуют и десериализуют SessionState.
  • Перехватчики Config.WrapSession и Config.UnwrapSession преобразуют SessionState в билет и обратно на стороне сервера.
  • Методы Config.EncryptTicket и Config.DecryptTicket предоставляют реализацию WrapSession и UnwrapSession по умолчанию.
  • Метод ClientSessionState.ResumptionState и функция NewResumptionState могут использоваться реализацией ClientSessionCache для хранения и возобновления сеансов на стороне клиента.

Чтобы уменьшить вероятность использования билетов сеанса в качестве механизма отслеживания между соединениями, сервер теперь выдает новые билеты при каждом возобновлении (если они поддерживаются и не отключены), и билеты больше не содержат идентификатор ключа, который их зашифровал. Передача большого количества ключей в Conn.SetSessionTicketKeys может привести к заметному снижению производительности.

И клиенты, и серверы теперь реализуют расширение Extended Master Secret (RFC 7627). Устаревание ConnectionState.TLSUnique отменено и теперь установлено для возобновленных соединений, поддерживающих расширенный главный секрет.

Новый тип QUICConn обеспечивает поддержку реализаций QUIC, включая поддержку 0-RTT. Обратите внимание, что это само по себе не является реализацией QUIC, и 0-RTT по-прежнему не поддерживается в TLS.

Новая функция VersionName возвращает имя для номера версии TLS.

Были улучшены коды предупреждений TLS, отправляемые с сервера при ошибках аутентификации клиента. Раньше эти сбои всегда приводили к предупреждению о "плохом сертификате". Теперь при определенных сбоях будут использоваться более подходящие коды предупреждений, как определено в RFC 5246 и RFC 8446:

  • Для подключений TLS 1.3, если сервер настроен на требование проверки подлинности клиента с помощью RequireAnyClientCert или RequireAndVerifyClientCert, а клиент не предоставляет сертификат, сервер теперь вернет предупреждение "требуется сертификат".
  • Если клиент предоставляет сертификат, который не подписан набором доверенных центров сертификации, настроенных на сервере, сервер вернет предупреждение "неизвестный центр сертификации".
  • Если клиент предоставляет сертификат, срок действия которого истек или еще не действителен, сервер вернет предупреждение "сертификат с истекшим сроком действия".
  • Во всех других сценариях, связанных с ошибками аутентификации клиента, сервер по-прежнему возвращает "неверный сертификат".

crypto/x509

RevokedList.RevokedCertificates устарел и заменен новым полем RevokedCertificateEntries, которое является частью RevokedListEntry. RelocationListEntry содержит все поля в pkix.RevokedCertificate, а также код причины отзыва.

Ограничения имен теперь правильно применяются к нелистовым сертификатам, а не к сертификатам, в которых они выражены.

debug/elf

Новый метод File.DynValue можно использовать для получения числовых значений, перечисленных в данном динамическом теге.

Постоянные флаги, разрешенные в динамическом теге DT_FLAGS_1, теперь определяются с типом DynFlag1. Эти теги имеют имена, начинающиеся с DF_1.

Пакет теперь определяет константу COMPRESS_ZSTD.

Пакет теперь определяет константу R_PPC64_REL24_P9NOTOC.

debug/pe

Попытки чтения из раздела, содержащего неинициализированные данные, с помощью Section.Data или средства чтения, возвращаемого Section.Open, теперь возвращают ошибку.

embed

io/fs.File, возвращаемый FS.Open, теперь имеет метод ReadAt, реализующий io.ReaderAt.

Вызов FS.Open.Stat вернет тип, который теперь реализует метод String, вызывающий io/fs.FormatFileInfo.

errors

Новая ошибка ErrUnsupported предоставляет стандартизированный способ указать, что запрошенная операция не может быть выполнена, поскольку она не поддерживается. Например, вызов os.Link при использовании файловой системы, не поддерживающей жесткие ссылки.

flag

Новая функция BoolFunc и метод FlagSet.BoolFunc определяют флаг, который не требует аргумента, и вызывает функцию при использовании флага. Это похоже на Func, но с логическим флагом.

Определение флага (через Bool, BoolVar, Int, IntVar и т. д.) вызовет панику, если Set уже был вызван для флага с таким же именем. Это изменение предназначено для обнаружения случаев, когда изменения в порядке инициализации приводят к тому, что операции с флагами выполняются в другом порядке, чем ожидалось. Во многих случаях решение этой проблемы состоит в том, чтобы ввести явную зависимость пакета, чтобы правильно упорядочить определение перед любыми операциями Set.

go/ast

Новый предикат IsGenerated сообщает, содержит ли синтаксическое дерево файла специальный комментарий, который обычно указывает на то, что файл был создан с помощью инструмента.

Новое поле File.GoVersion записывает минимальную версию Go, необходимую для любых директив //go:build или // +build.

go/build

Пакет теперь анализирует директивы сборки (комментарии, начинающиеся с //go:) в заголовках файлов (перед объявлением пакета). Эти директивы доступны в новых полях пакета: Directives, TestDirectives и XTestDirectives.

go/build/constraint

Новая функция GoVersion возвращает минимальную версию Go, подразумеваемую выражением сборки.

go/token

Новый метод File.Lines возвращает таблицу номеров строк файла в той же форме, которая принята File.SetLines.

go/types

Новый метод Package.GoVersion возвращает версию языка Go, использованную для проверки пакета.

hash/maphash

Пакет hash/maphash теперь имеет реализацию на чистом Go, которую можно выбрать с помощью тега сборки purego.

html/template

Новая ошибка ErrJSTemplate возвращается, когда действие появляется в литерале шаблона JavaScript. Ранее возвращалась неэкспортированная ошибка.

io/fs

Новая функция FormatFileInfo возвращает отформатированную версию FileInfo. Новая функция FormatDirEntry возвращает отформатированную версию DirEntry. Реализация DirEntry, возвращаемая ReadDir, теперь реализует метод String, который вызывает FormatDirEntry, и то же самое справедливо для значения DirEntry, переданного в WalkDirFunc.

math/big

Новый метод Int.Float64 возвращает ближайшее целое число с плавающей запятой вместе с указанием любого произошедшего округления.

net

В Linux пакет net теперь может использовать Multipath TCP, если ядро его поддерживает. По умолчанию он не используется. Чтобы использовать Multipath TCP, если он доступен на клиенте, вызовите метод Dialer.SetMultipathTCP перед вызовом методов Dialer.Dial или Dialer.DialContext. Чтобы использовать Multipath TCP, если он доступен на сервере, вызовите метод ListenConfig.SetMultipathTCP перед вызовом метода ListenConfig.Listen. Укажите сеть как "tcp", "tcp4" или "tcp6", как обычно. Если Multipath TCP не поддерживается ядром или удаленным хостом, соединение автоматически переключается на TCP. Чтобы проверить, использует ли конкретное соединение Multipath TCP, используйте метод TCPConn.MultipathTCP.

В будущем релизе Go возможно будет включен Multipath TCP по умолчанию в системах, которые его поддерживают.

net/http

Новый метод ResponseController.EnableFullDuplex позволяет обработчикам сервера одновременно читать тело запроса HTTP/1 во время записи ответа. Обычно сервер HTTP/1 автоматически потребляет оставшееся тело запроса перед началом записи ответа, чтобы избежать взаимоблокировки клиентов, которые пытаются записать полный запрос до чтения ответа. Метод EnableFullDuplex отключает такое поведение.

Новая ошибка ErrSchemeMismatch возвращается клиентом и транспортом, когда сервер отвечает на запрос HTTPS ответом HTTP.

Пакет net/http теперь поддерживает error.ErrUnsupported, поскольку выражение error.Is(http.ErrNotSupported, error.ErrUnsupported) вернет true.

os

Программы теперь могут передавать пустое значение time.Time функции Chtimes, чтобы оставить неизменным либо время доступа, либо время модификации.

В Windows метод File.Chdir теперь меняет текущий каталог на файл, а не всегда возвращает ошибку.

В системах Unix, если в NewFile передается неблокирующий дескриптор, вызов метода File.Fd теперь будет возвращать неблокирующий дескриптор. Ранее дескриптор был переведен в режим блокировки.

В Windows вызов Truncate для несуществующего файла используется для создания пустого файла. Теперь он возвращает ошибку, указывающую, что файл не существует.

В Windows при вызове TempDir теперь используется GetTempPath2W, если он доступен, вместо GetTempPathW. Новое поведение представляет собой меру усиления безопасности, которая предотвращает доступ к временным файлам, созданным процессами, работающими как SYSTEM, со стороны не-SYSTEM процессов.

В Windows пакет os теперь поддерживает работу с файлами, имена которых, сохраненные в формате UTF-16, не могут быть представлены как действительные UTF-8.

В Windows Lstat теперь разрешает символические ссылки для путей, заканчивающихся разделителем путей, в соответствии с его поведением на платформах POSIX.

Реализация интерфейса io/fs.DirEntry, возвращаемого функцией ReadDir и методом File.ReadDir, теперь реализует метод String, который вызывает io/fs.FormatDirEntry.

Реализация интерфейса io/fs.FS, возвращаемого функцией DirFS, теперь реализует интерфейсы io/fs.ReadFileFS и io/fs.ReadDirFS.

path/filepath

Реализация интерфейса io/fs.DirEntry, передаваемого в аргумент функции WalkDir, теперь реализует метод String, который вызывает io/fs.FormatDirEntry.

reflect

В Go 1.21 ValueOf больше не принудительно размещает свой аргумент в куче, позволяя размещать содержимое Value в стеке. Большинство операций с Value также позволяют размещать базовое значение в стеке.

Новый метод Value Value.Clear очищает содержимое карты или обнуляет содержимое среза. Это соответствует новой встроенной функции clear, добавленной в язык.

Типы SliceHeader и StringHeader устарели. В новом коде отдавайте предпочтение unsafe.Slice, unsafe.SliceData, unsafe.String или unsafe.StringData.

regexp

Regexp теперь определяет методы MarshalText и UnmarshalText. Они реализуют encoding.TextMarshaler и encoding.TextUnmarshaler и будут использоваться такими пакетами, как encoding/json.

runtime

Текстовые трассировки стека, создаваемые программами Go, например, при сбое, вызове runtime.Stack или сборе профиля горутины с debug=2, теперь включают в трассировку стека идентификаторы горутин, создавших каждую горутину.

Сбойные приложения Go теперь могут подключиться к отчетам об ошибках Windows (WER, Windows Error Reporting), установив переменную среды GOTRACEBACK=wer или вызвав debug.SetTraceback("wer") перед сбоем. За исключением включения WER, среда выполнения будет вести себя так же, как и при GOTRACEBACK=crash. В системах, отличных от Windows, GOTRACEBACK=wer игнорируется.

GODEBUG=cgocheck=2, тщательная проверка правил передачи указателей cgo, больше не доступен в качестве опции отладки. Вместо этого он доступен в качестве эксперимента с использованием GOEXPERIMENT=cgocheck2. В частности, это означает, что этот режим необходимо выбирать во время сборки, а не во время запуска.

GODEBUG=cgocheck=1 по-прежнему доступен (и по-прежнему используется по умолчанию).

В пакет среды выполнения добавлен новый тип Pinner. Пиннеры могут использоваться для "закрепления" памяти Go, чтобы ее можно было более свободно использовать кодом, отличным от Go. Например, теперь разрешена передача значений Go, которые ссылаются на закрепленную память Go, в код C. Ранее передача любой такой вложенной ссылки была запрещена правилами передачи указателей cgo.

runtime/metrics

Теперь доступны некоторые ранее внутренние показатели сборщика мусора, такие как размер динамической кучи. GOGC и GOMEMLIMIT теперь также доступны в качестве метрик.

runtime/trace

Сбор трассировок на amd64 и arm64 теперь требует существенно меньших затрат ЦП: до 10 раз больше, чем в предыдущей версии.

Трассировки теперь содержат явные события stop-the-world по любой причине, по которой среда выполнения Go может запустить stop-the-world, а не только для сборки мусора.

sync

Новые функции OnceFunc, OnceValue и OnceValues отражают распространенное использование Once для ленивой инициализации значения при первом использовании.

syscall

В Windows функция Fchdir теперь меняет текущий каталог на свой аргумент, а не всегда возвращает ошибку.

Во FreeBSD SysProcAttr имеет новое поле Jail, которое можно использовать для помещения вновь созданного процесса в изолированную среду.

В Windows пакет syscall теперь поддерживает работу с файлами, имена которых, сохраненные в формате UTF-16, не могут быть представлены как допустимые UTF-8. Функции UTF16ToString и UTF16FromString теперь преобразуют данные UTF-16 в строки WTF-8. Это обратно совместимо, поскольку WTF-8 является расширенным набором формата UTF-8, который использовался в более ранних релизах.

Несколько значений ошибок соответствуют новым error.ErrUnsupported, например, error.Is(err, error.ErrUnsupported) возвращает true.

  • ENOSYS
  • ENOTSUP
  • EOPNOTSUPP
  • EPLAN9 (только Plan 9)
  • ERROR_CALL_NOT_IMPLEMENTED (только Windows)
  • ERROR_NOT_SUPPORTED (только Windows)
  • EWINDOWS (только Windows)

testing

Новая опция -test.fullpath будет печатать полные пути в сообщениях журнала тестирования, а не только базовые имена.

Новая функция тестирования сообщает, является ли программа тестом, созданным go test.

testing/fstest

Вызов Open.Stat вернет тип, который теперь реализует метод String, вызывающий io/fs.FormatFileInfo.

unicode

Пакет unicode и связанная с ним поддержка во всей системе были обновлены до Unicode 15.0.0.

Порты

Darwin

Как объявлено в примечаниях к релизу Go 1.20, для Go 1.21 требуется macOS 10.15 Catalina или более поздняя версия; поддержка предыдущих версий прекращена.

Windows

Как объявлено в примечаниях к релизу Go 1.20, для Go 1.21 требуется как минимум Windows 10 или Windows Server 2016; поддержка предыдущих версий прекращена.

WebAssembly

Новую директиву go:wasmimport теперь можно использовать в программах Go для импорта функций с хоста WebAssembly.

Планировщик Go теперь гораздо эффективнее взаимодействует с циклом событий JavaScript, особенно в приложениях, которые часто блокируются при асинхронных событиях.

Системный интерфейс WebAssembly

В Go 1.21 добавлен экспериментальный порт в системный интерфейс WebAssembly (WASI), предварительная версия 1 (GOOS=wasip1, GOARCH=wasm).

В результате добавления нового значения GOOS "wasip1" файлы Go с именем *_wasip1.go теперь будут игнорироваться инструментами Go, за исключением случаев, когда используется это значение GOOS. Если у вас есть имена файлов, соответствующие этому шаблону, вам нужно будет переименовать их.

ppc64/ppc64le

В Linux GOPPC64=power10 теперь генерирует инструкции для PC, инструкции с префиксами и другие новые инструкции Power10. В AIX GOPPC64=power10 генерирует инструкции Power10, но не создает инструкции, относящиеся к PC.

При построении позиционно-независимых двоичных файлов для GOPPC64=power10 GOOS=linux GOARCH=ppc64le пользователи могут ожидать уменьшения размера двоичных файлов в большинстве случаев, в некоторых случаях на 3,5%. Независимые от позиции двоичные файлы создаются для ppc64le со следующими значениями -buildmode: c-archive, c-shared, shared, pie, plugin.

loong64

Порт linux/loong64 теперь поддерживает -buildmode=c-archive, -buildmode=c-shared и -buildmode=pie.


Читайте также:


купить игрушку gopher

вторник, 21 февраля 2023 г.

Релиз Go 1.20

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

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

Go 1.20 включает четыре изменения языка.

В Go 1.17 добавлены преобразования из среза в указатель массива. Go 1.20 расширяет это, чтобы разрешить преобразования из среза в массив: для среза x теперь можно записать [4]byte(x) вместо *(*[4]byte)(x).

Пакет unsafe определяет три новые функции SliceData, String и StringData. Наряду с Slice из Go 1.17 эти функции теперь предоставляют полную возможность конструировать и деконструировать значения срезов и строк, не завися от их точного представления.

Спецификация теперь определяет, что значения структуры сравниваются по одному полю за раз, рассматривая поля в том порядке, в котором они появляются в определении типа структуры, и останавливаясь при первом несоответствии. Раньше можно было прочитать спецификацию так, как будто нужно сравнивать все поля, кроме первого несоответствия. Точно так же спецификация теперь определяет, что значения массива сравниваются по одному элементу за раз в порядке возрастания индекса. В обоих случаях разница влияет на то, должны ли определенные сравнения вызывать панику. Существующие программы не изменились: новая формулировка спецификации описывает то, что всегда делали реализации.

Сопоставимые типы (такие как обычные интерфейсы) теперь могут удовлетворять сравнимым ограничениям, даже если аргументы типа не являются строго сравнимыми (сравнение может прерываться во время выполнения). Это позволяет создать экземпляр параметра типа, ограниченного параметром сравнения (например, параметр типа для определяемого пользователем универсального ключа карты) с аргументом типа, не являющимся строго сравнимым, таким как тип интерфейса или составной тип, содержащий тип интерфейса.

Порты


Windows

Go 1.20 — это последний релиз, который будет работать в любой версии Windows 7, 8, Server 2008 и Server 2012. Для Go 1.21 потребуется как минимум Windows 10 или Server 2016.

Darwin и iOS

Go 1.20 — это последний релиз, который будет работать на macOS 10.13 High Sierra или 10.14 Mojave. Go 1.21 потребует macOS 10.15 Catalina или более поздней версии.

FreeBSD/RISC-V

Go 1.20 добавляет экспериментальную поддержку FreeBSD на RISC-V (GOOS=freebsd, GOARCH=riscv64).

Инструменты


Команда go

Каталог $GOROOT/pkg больше не хранит предварительно скомпилированные архивы пакетов для стандартной библиотеки: go install больше не записывает их, сборка go больше не проверяет их, и дистрибутив Go больше не отправляет их. Вместо этого пакеты в стандартной библиотеке собираются по мере необходимости и кэшируются в кэше сборки, как и пакеты вне GOROOT. Это изменение уменьшает размер дистрибутива Go, а также позволяет избежать перекоса инструментальной цепочки C для пакетов, использующих cgo.

Реализация go test -json была улучшена, чтобы сделать ее более надежной. Программы, запускающие go test -json, не нуждаются в каких-либо обновлениях. Программы, которые напрямую вызывают инструмент go test2json, теперь должны запускать двоичный файл теста с параметром -v=test2json (например, go test -v=test2json или ./pkg.test -test.v=test2json) вместо простого -v.

Связанное с этим изменение для go test -json — это добавление события с набором действий для запуска в начале выполнения каждой тестовой программы. При запуске нескольких тестов с помощью команды go эти стартовые события гарантированно будут генерироваться в том же порядке, что и пакеты, указанные в командной строке.

Команда go теперь определяет теги построения функций архитектуры, такие как amd64.v2, чтобы позволить выбрать файл реализации пакета на основе наличия или отсутствия конкретной функции архитектуры.

Подкоманды go теперь принимают -C <dir> для изменения каталога на <dir> перед выполнением команды, что может быть полезно для сценариев, которым необходимо выполнять команды в нескольких разных модулях.

Команды go build и go test больше не принимают флаг -i, который устарел, начиная с Go 1.16.

Команда go generate теперь принимает -skip <pattern> для пропуска директив //go:generate, соответствующих <pattern>.

Команда go test теперь принимает параметр -skip <pattern>, чтобы пропустить тесты, подтесты или примеры, соответствующие <pattern>.

Когда основной модуль находится в GOPATH/src, go install больше не устанавливает библиотеки для неосновных пакетов в GOPATH/pkg, а go list больше не сообщает поле Target для таких пакетов. (В модульном режиме скомпилированные пакеты хранятся только в кэше сборки, но из-за ошибки цели установки GOPATH неожиданно остались в силе.)

Команды go build, go install и другие, связанные со сборкой, теперь поддерживают флаг -pgo, который включает оптимизацию на основе профиля. Флаг -pgo указывает путь к файлу профиля. Указание -pgo=auto заставляет команду go искать файл с именем default.pgo в каталоге пакета main и использовать его, если он есть. В настоящее время для этого режима требуется, чтобы в командной строке был указан один main пакет, но планируется снять это ограничение в будущем релизе. Указание -pgo=off отключает оптимизацию на основе профиля.

Команды go build, go install и другие команды, связанные со сборкой, теперь поддерживают флаг -cover, который выполняет сборку указанной цели с инструментированием покрытия кода.

go version

Команда go version -m теперь поддерживает чтение дополнительных типов двоичных файлов Go, в первую очередь библиотек DLL Windows, созданных с помощью go build -buildmode=c-shared, и двоичных файлов Linux без разрешения на выполнение.

Cgo

Команда go теперь отключает cgo по умолчанию в системах без цепочки инструментов C. В частности, когда переменная среды CGO_ENABLED не установлена, переменная среды CC не установлена, а компилятор C по умолчанию (обычно clang или gcc) не найден в пути, CGO_ENABLED по умолчанию имеет значение 0. Как всегда, вы можете переопределить значение по умолчанию, установка CGO_ENABLED явно.

Наиболее важным эффектом изменения по умолчанию является то, что когда Go устанавливается в системе без компилятора C, теперь он будет использовать чистые сборки Go для пакетов в стандартной библиотеке, которые используют cgo, вместо использования предустановленных архивов пакетов (которые были удалены, как указано выше) или попытки использовать cgo и неудаче при этом. Это позволяет Go лучше работать в некоторых средах с минимальным контейнером, а также в macOS, где предустановленные архивы пакетов не использовались для пакетов на основе cgo, начиная с версии Go 1.16.

Пакеты в стандартной библиотеке, использующие cgo, это net, os/user и plugin. В macOS пакеты net и os/user были переписаны, чтобы не использовать cgo: теперь один и тот же код используется для сборок cgo и не-cgo, а также кросс-компилируемых сборок. В Windows пакеты net и os/user никогда не использовали cgo. В других системах сборки с отключенным cgo будут использовать чистую версию Go этих пакетов.

В macOS детектор гонок был переписан, чтобы не использовать cgo: программы с включенным детектором гонок можно создавать и запускать без Xcode. В Linux и других системах Unix, а также в Windows для использования детектора гонки требуется цепочка инструментов C на хосте.

Cover (Покрытие)

Go 1.20 поддерживает сбор профилей покрытия кода для программ (приложений и интеграционных тестов), а не только модульных тестов.

Чтобы собрать данные о покрытии для программы, соберите ее с флагом -cover команды go build, затем запустите полученный двоичный файл с переменной среды GOCOVERDIR, установленной в выходной каталог для профилей покрытия.

Ветеринар (vet)

Улучшено обнаружение захвата переменных цикла вложенными функциями.

Инструмент vet теперь сообщает о ссылках на переменные цикла после вызова T.Parallel() в телах функций подтеста. В таких ссылках может наблюдаться значение переменной из другой итерации (что обычно приводит к пропуску тестовых случаев) или недопустимое состояние из-за несинхронизированного конкурентного доступа.

Инструмент также обнаруживает ошибки ссылок в большем количестве мест. Раньше он рассматривал только последний оператор тела цикла, но теперь он рекурсивно проверяет последние операторы в операторах if, switch и select.

Новая диагностика для некорректных форматов времени

Инструмент vet теперь сообщает об использовании формата времени 2006-02-01 (гггг-дд-мм) с Time.Format и time.Parse. Этот формат не встречается в общих стандартах даты, но часто используется по ошибке при попытке использовать формат даты ISO 8601 (гггг-мм-дд).

Runtime

Некоторые из внутренних структур данных сборщика мусора были реорганизованы, чтобы освободить больше места и CPU. Это изменение снижает нагрузку на память и повышает общую производительность процессора до 2%.

В некоторых случаях сборщик мусора ведет себя менее беспорядочно по отношению к горутине.

Go 1.20 добавляет новый пакет runtime/coverage, содержащий API для записи данных профиля покрытия во время выполнения из долго работающих и/или серверных программ, которые не завершаются через os.Exit().

Компилятор

В Go 1.20 добавлена предварительная поддержка оптимизации на основе профиля (PGO). PGO позволяет цепочке инструментов выполнять оптимизацию для конкретных приложений и рабочих нагрузок на основе информации о профиле времени выполнения. В настоящее время компилятор поддерживает профили CPU pprof, которые можно собирать обычными средствами, такими как пакеты runtime/pprof или net/http/pprof. Чтобы включить PGO, передайте путь к файлу профиля pprof через флаг -pgo, чтобы начать сборку, как указано выше. Go 1.20 использует PGO для более агрессивного встраивания функций в местах горячих вызовов. Тесты для репрезентативного набора программ Go показывают, что включение оптимизации встраивания на основе профиля повышает производительность примерно на 3–4%. Планируется добавить больше оптимизаций на основе профилей в будущих релизах. Обратите внимание, что оптимизация на основе профилей является предварительной версией, поэтому используйте ее с осторожностью.

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

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

В Go 1.18 и 1.19 наблюдался регресс в скорости сборки, в основном из-за добавления поддержки дженериков и последующей работы. Go 1.20 повышает скорость сборки до 10 %, возвращая ее в соответствие с Go 1.17. По сравнению с Go 1.19 производительность сгенерированного кода также в целом немного улучшилась.

Линкер (компоновщик)

В Linux компоновщик теперь выбирает динамический интерпретатор для glibc или musl во время компоновки.

В Windows компоновщик Go теперь поддерживает современные наборы инструментов C на основе LLVM.

Go 1.20 использует префиксы go: и type: для символов, сгенерированных компилятором, а не go. и type. . Это позволяет избежать путаницы для пользовательских пакетов, имя которых начинается с go. . Пакет debug/gosym понимает это новое соглашение об именах для двоичных файлов, созданных с помощью Go 1.20 и новее.

Начальная загрузка (Bootstrap)

При сборке релиза Go из исходного кода и не заданном GOROOT_BOOTSTRAP предыдущие версии Go искали цепочку инструментов начальной загрузки Go 1.4 или более поздней версии в каталоге $HOME/go1.4 (%HOMEDRIVE%%HOMEPATH%\go1.4 в Windows). Go 1.18 и Go 1.19 сначала искали $HOME/go1.17 или $HOME/sdk/go1.17, а затем возвращались к $HOME/go1.4, ожидая, что Go 1.17 потребуется для использования при начальной загрузке Go 1.20. Go 1.20 требует версии Go 1.17 для начальной загрузки, но стало понятно, что следует использовать последнюю точечную версию цепочки инструментов начальной загрузки, поэтому для нее требуется Go 1.17.13. Go 1.20 ищет $HOME/go1.17.13 или $HOME/sdk/go1.17.13, прежде чем вернуться к $HOME/go1.4 (для поддержки систем, которые жестко запрограммировали путь $HOME/go1.4, но установили более новый Go туда). В будущем планируется продвигать цепочку инструментов начальной загрузки примерно раз в год, и, в частности, ожидается, что Go 1.22 потребует финальной версии Go 1.20 для начальной загрузки.

Основная библиотека


Новый пакет crypto/ecdh

Go 1.20 добавляет новый пакет crypto/ecdh для обеспечения явной поддержки обмена ключами Диффи-Хеллмана на эллиптических кривых по кривым NIST и Curve25519.

Программы должны использовать crypto/ecdh вместо функций более низкого уровня в crypto/elliptic для ECDH и сторонние модули для более продвинутых вариантов использования.

Обертывание нескольких ошибок

Go 1.20 расширяет поддержку обертывания ошибок, позволяя одной ошибке оборачивать несколько других ошибок.

Ошибка e может обернуть более одной ошибки, предоставив метод Unwrap, который возвращает []error.

Функции errors.Is и errors.As были обновлены для проверки многократно обернутых ошибок.

Функция fmt.Errorf теперь поддерживает несколько вхождений глагола форматирования %w, из-за чего она возвращает ошибку, обертывающую все эти операнды ошибок.

Новая функция errors.Join возвращает ошибку, обертывающую список ошибок.

HTTP ResponseController

Новый тип "net/http".ResponseController предоставляет доступ к расширенным функциям для каждого запроса, которые не обрабатываются интерфейсом "net/http".ResponseWriter.

Ранее были добавилены новые функции для каждого запроса, определив необязательные интерфейсы, которые может реализовать ResponseWriter, например Flusher. Эти интерфейсы не обнаруживаются и неуклюжи в использовании.

Тип ResponseController обеспечивает более понятный и удобный способ добавления элементов управления для каждого обработчика. В Go 1.20 также добавлены два таких элемента управления: SetReadDeadline и SetWriteDeadline, которые позволяют устанавливать крайние сроки чтения и записи для каждого запроса. Например:

func RequestHandler(w ResponseWriter, r *Request) {
  rc := http.NewResponseController(w)
  rc.SetWriteDeadline(time.Time{}) // отключаем Server.WriteTimeout при отправке большого ответа
  io.Copy(w, bigData)
}

Новый хук ReverseProxy Rewrite

Прокси-сервер пересылки httputil.ReverseProxy включает новую функцию хука Rewrite, заменяющую предыдущий хук Director.

Хук Rewrite принимает параметр ProxyRequest, который включает в себя как входящий запрос, полученный прокси-сервером, так и исходящий запрос, который он отправит. В отличие от хуков Director, которые работают только с исходящим запросом, это позволяет хукам Rewrite избегать определенных сценариев, когда злонамеренный входящий запрос может привести к удалению заголовков, добавленных хуком, перед пересылкой.

Метод ProxyRequest.SetURL направляет исходящий запрос в указанное место назначения и заменяет функцию NewSingleHostReverseProxy. В отличие от NewSingleHostReverseProxy, SetURL также устанавливает заголовок узла исходящего запроса.

Метод ProxyRequest.SetXForwarded устанавливает заголовки X-Forwarded-For, X-Forwarded-Host и X-Forwarded-Proto исходящего запроса. При использовании Rewrite эти заголовки не добавляются по умолчанию.

Пример хука Rewrite, использующего эти функции:

proxyHandler := &httputil.ReverseProxy{
  Rewrite: func(r *httputil.ProxyRequest) {
    r.SetURL(outboundURL) // Перенаправить запрос на исходящий URL.
    r.SetXForwarded()     //  Установить заголовки X-Forwarded-*.
    r.Out.Header.Set("X-Additional-Header", "header set by the proxy")
  },
}

ReverseProxy больше не добавляет заголовок User-Agent к пересылаемым запросам, если во входящем запросе его нет.

Мелкие изменения в библиотеке

Как всегда, в библиотеку внесены различные незначительные изменения и обновления, сделанные с учетом обещания совместимости с Go 1. Существуют также различные улучшения производительности, не перечисленные здесь.

archive/tar

Если установлена переменная среды GODEBUG=tarinsecurepath=0, метод Reader.Next теперь будет возвращать ошибку ErrInsecurePath для записи с именем файла, которое является абсолютным путем, ссылается на расположение за пределами текущего каталога, содержит недопустимые символы или (в Windows) — это зарезервированное имя, такое как NUL. В будущей версии Go небезопасные пути могут быть отключены по умолчанию.

archive/zip

Если установлена переменная окружения GODEBUG=zipinsecurepath=0, NewReader теперь будет возвращать ошибку ErrInsecurePath при открытии архива, содержащего любое имя файла, которое является абсолютным путем, ссылается на расположение за пределами текущего каталога, содержит недопустимые символы или (на Windows) — это зарезервированные имена, такие как NUL. В будущей версии Go небезопасные пути могут быть отключены по умолчанию.

Чтение из файла каталога, содержащего данные файла, теперь будет возвращать ошибку. Спецификация zip не позволяет файлам каталогов содержать файловые данные, поэтому это изменение влияет только на чтение из недопустимых архивов.

bytes

Новые функции CutPrefix и CutSuffix похожи на TrimPrefix и TrimSuffix, но также сообщают, была ли строка обрезана.

Новая функция Clone выделяет копию байтового среза.

context

Новая функция WithCancelCause предоставляет способ отменить контекст с заданной ошибкой. Эту ошибку можно получить, вызвав новую функцию Cause.

crypto/ecdsa

При использовании поддерживаемых кривых все операции теперь выполняются за постоянное время. Это привело к увеличению процессорного времени от 5% до 30%, в основном затронув P-384 и P-521.

Новый метод PrivateKey.ECDH преобразует ecdsa.PrivateKey в ecdh.PrivateKey.

crypto/ed25519

Метод PrivateKey.Sign и функция VerifyWithOptions теперь поддерживают подписание предварительно хэшированных сообщений с помощью Ed25519ph, на что указывает Options.HashFunc, возвращающий crypto.SHA512. Кроме того, теперь они поддерживают Ed25519ctx и Ed25519ph с контекстом, указанным в новом поле Options.Context.

crypto/rsa

Новое поле OAEPOptions.MGFHash позволяет отдельно настроить хэш MGF1 для расшифровки OAEP.

crypto/rsa теперь использует новый, более безопасный бекенд с постоянным временем. Это приводит к увеличению времени выполнения ЦП для операций расшифровки примерно на 15% (RSA-2048 на amd64) до 45% (RSA-4096 на arm64) и больше на 32-разрядных архитектурах. Операции шифрования примерно в 20 раз медленнее, чем раньше (но все же в 5-10 раз быстрее, чем дешифрование). Ожидается, что производительность улучшится в будущих релизах. Программы не должны изменять или создавать вручную поля PrecomputedValues.

crypto/subtle

Новая функция XORBytes XOR объединяет два байтовых среза.

crypto/tls

Проанализированные сертификаты теперь совместно используются всеми клиентами, активно использующими этот сертификат. Экономия памяти может быть значительной в программах, которые выполняют множество одновременных подключений к серверу или набору серверов, совместно использующих любую часть своих цепочек сертификатов.

При сбое рукопожатия из-за сбоя проверки сертификата клиент и сервер TLS теперь возвращают ошибку нового типа CertificateVerificationError, которая включает представленные сертификаты.

crypto/x509

ParsePKCS8PrivateKey и MarshalPKCS8PrivateKey теперь поддерживают ключи типа *crypto/ecdh.PrivateKey. ParsePKIXPublicKey и MarshalPKIXPublicKey теперь поддерживают ключи типа *crypto/ecdh.PublicKey. Анализ ключей кривой NIST по-прежнему возвращает значения типа *ecdsa.PublicKey и *ecdsa.PrivateKey. Используйте их новые методы ECDH для преобразования в типы crypto/ecdh.

Новая функция SetFallbackRoots позволяет программе определить набор резервных корневых сертификатов на случай, если верификатор операционной системы или стандартный корневой пакет платформы недоступен во время выполнения. Чаще всего он будет использоваться с новым пакетом golang.org/x/crypto/x509roots/fallback, который предоставит обновленный корневой пакет.

debug/elf

Попытки чтения из раздела SHT_NOBITS с помощью Section.Data или средства чтения, возвращенного Section.Open, теперь возвращают ошибку.

Дополнительные константы R_LARCH_* определены для использования с системами LoongArch.

Дополнительные константы R_PPC64_* определены для использования с перемещениями PPC64 ELFv2.

Значение константы для R_PPC64_SECTOFF_LO_DS исправлено с 61 на 62.

debug/gosym

В связи с изменением правил именования символов Go инструменты, обрабатывающие двоичные файлы Go, должны использовать пакет debug/gosym версии 1.20 для прозрачной обработки как старых, так и новых двоичных файлов.

debug/pe

Дополнительные константы IMAGE_FILE_MACHINE_RISCV* определены для использования с системами RISC-V.

encoding/binary

Функции ReadVarint и ReadUvarint теперь будут возвращать io.ErrUnexpectedEOF после чтения частичного значения, а не io.EOF.

encoding/xml

Новый метод Encoder.Close можно использовать для проверки незакрытых элементов после завершения кодирования.

Теперь декодер отклоняет имена элементов и атрибутов, содержащие более одного двоеточия, такие как <a:b:c>, а также пространства имен, которые разрешаются в пустую строку, например xmlns:a="".

Декодер теперь отклоняет элементы, которые используют разные префиксы пространства имен в открывающем и закрывающем теге, даже если оба этих префикса обозначают одно и то же пространство имен.

errors

Новая функция Join возвращает ошибку, обертывающую список ошибок.

fmt

Функция Errorf поддерживает несколько вхождений глагола формата %w, возвращая ошибку, которая разворачивается в список всех аргументов %w.

Новая функция FormatString восстанавливает директиву форматирования, соответствующую состоянию, что может быть полезно в Formatter. реализации.

go/ast

Новое поле RangeStmt.Range записывает положение ключевого слова диапазона в операторе диапазона.

В новых полях File.FileStart и File.FileEnd записывается положение начала и конца всего исходного файла.

go/token

Новый метод FileSet.RemoveFile удаляет файл из набора файлов. Долго работающие программы могут использовать это для освобождения памяти, связанной с файлами, которые им больше не нужны.

go/types

Новая функция Satisfies сообщает, удовлетворяет ли тип ограничениям. Это изменение согласуется с новой языковой семантикой, которая отличает удовлетворение ограничения от реализации интерфейса.

io

Новый OffsetWriter является оболочкой базового WriterAt и предоставляет методы Seek, Write и WriteAt, которые корректируют их эффективную позицию смещения в файле на фиксированную величину.

io/fs

Новая ошибка SkipAll немедленно, но успешно завершает WalkDir.

math/big

Широкая область применения пакета math/big и время, зависящее от ввода, делают его плохо подходящим для реализации криптографии. Пакеты криптографии в стандартной библиотеке больше не вызывают нетривиальные методы Int для входных данных, контролируемых злоумышленником. В будущем определение того, считается ли ошибка в math/big уязвимостью системы безопасности, будет зависеть от ее более широкого влияния на стандартную библиотеку.

math/rand

Пакет math/rand теперь автоматически заполняет глобальный генератор случайных чисел (используемый функциями верхнего уровня, такими как Float64 и Int) случайным значением, а функция Seed верхнего уровня устарела. Программы, которым нужна воспроизводимая последовательность случайных чисел, должны предпочитать выделять свой собственный источник случайных чисел, используя rand.New(rand.NewSource(seed)).

Программы, которым требуется более раннее последовательное глобальное заполнение, могут установить GODEBUG=randautoseed=0 в своей среде.

Функция чтения верхнего уровня устарела. Почти во всех случаях лучше подходит crypto/rand.Read.

mime

Функция ParseMediaType теперь позволяет дублировать имена параметров, если значения имен совпадают.

mime/multipart

Методы типа Reader теперь оборачивают ошибки, возвращаемые базовым io.Reader.

net

Функция LookupCNAME теперь последовательно возвращает содержимое записи CNAME, если она существует. Раньше в системах Unix и при использовании чистого преобразователя Go функция LookupCNAME возвращала ошибку, если запись CNAME ссылалась на имя без записи A, AAAA или CNAME. Это изменение изменяет LookupCNAME, чтобы оно соответствовало предыдущему поведению в Windows, позволяя успешно выполнять LookupCNAME всякий раз, когда CNAME существует.

Interface.Flags теперь включает новый флаг FlagRunning, указывающий на операционно активный интерфейс. Для интерфейса, настроенного административно, но неактивного (например, из-за того, что сетевой кабель не подключен), будет установлен FlagUp, но не FlagRunning.

Новое поле Dialer.ControlContext содержит функцию обратного вызова, аналогичную существующему хуку Dialer.Control, который дополнительно принимает контекст набора в качестве параметра. Управление игнорируется, если ControlContext не равен нулю.

Сопоставитель Go DNS распознает вариант сопоставителя trust-ad. Когда в resolv.conf установлены параметры trust-ad, преобразователь Go будет устанавливать бит AD в DNS-запросах. Преобразователь не использует бит AD в ответах.

Разрешение DNS обнаружит изменения в /etc/nsswitch.conf и перезагрузит файл при его изменении. Проверки выполняются не чаще одного раза каждые пять секунд, что соответствует предыдущей обработке файлов /etc/hosts и /etc/resolv.conf.

net/http

Функция ResponseWriter.WriteHeader теперь поддерживает отправку кодов состояния 1xx.

Новый параметр конфигурации Server.DisableGeneralOptionsHandler позволяет отключить обработчик OPTIONS * по умолчанию.

Новый хук Transport.OnProxyConnectResponse вызывается, когда Transport получает HTTP-ответ от прокси-сервера на запрос CONNECT.

HTTP-сервер теперь принимает запросы HEAD, содержащие тело, а не отклоняет их как недействительные.

Ошибки потока HTTP/2, возвращаемые функциями net/http, могут быть преобразованы в golang.org/x/net/http2.StreamError с помощью errors.As.

Начальные и конечные пробелы удаляются из имен файлов cookie, а не отклоняются как недействительные. Например, параметр файла cookie
"имя =значение" теперь принимается как параметр "имя" файла cookie.

net/netip

Новые функции IPv6LinkLocalAllRouters и IPv6Loopback являются эквивалентами net/netip функций net.IPv6loopback и net.IPv6linklocalallrouters.

os

В Windows имя NUL больше не рассматривается как особый случай в Mkdir и Stat.

В Windows File.Stat теперь использует дескриптор файла для получения атрибутов, когда файл является каталогом. Ранее он использовал путь, переданный в Open, который больше не может быть файлом, представленным дескриптором файла, если файл был перемещен или заменен. Это изменение изменяет Open для открытия каталогов без доступа FILE_SHARE_DELETE, что соответствует поведению обычных файлов.

В Windows File.Seek теперь поддерживает поиск в начале каталога.

os/exec

Новые поля Cmd Cancel и WaitDelay определяют поведение Cmd, когда связанный с ним контекст отменяется или его процесс завершается, а каналы ввода-вывода остаются открытыми дочерним процессом.

path/filepath

Новая ошибка SkipAll немедленно, но успешно завершает Walk.

Новая функция IsLocal сообщает, является ли путь лексически локальным для каталога. Например, если IsLocal(p) имеет значение true, то Open(p) будет ссылаться на файл, который лексически находится внутри поддерева с корнем в текущем каталоге.

reflect

Новые методы Value.Comparable и Value.Equal можно использовать для сравнения двух значений на предмет равенства. Comparable сообщает, является ли Equal допустимой операцией для данного приемника Value.

Новый метод Value.Grow расширяет срез, чтобы гарантировать место для других n элементов.

Новый метод Value.SetZero задает нулевое значение для своего типа.

Go 1.18 представил методы Value.SetIterKey и Value.SetIterValue. Это оптимизации: v.SetIterKey(it) должен быть эквивалентен v.Set(it.Key()). Реализации ошибочно пропускали проверку на использование неэкспортированных полей, которая присутствовала в неоптимизированных формах. Go 1.20 исправляет эти методы, чтобы включить проверку неэкспортированных полей.

regexp

Go 1.19.2 и Go 1.18.7 включали исправление безопасности для синтаксического анализатора регулярных выражений, заставляющее его отклонять очень большие выражения, которые потребляли бы слишком много памяти. Поскольку релизы исправлений Go не вводят новый API, синтаксический анализатор в этом случае вернул синтаксис.ErrInternalError. В Go 1.20 добавлена более конкретная ошибка syntax.ErrLarge, которую теперь возвращает синтаксический анализатор.

runtime/cgo

Go 1.20 добавляет новый тип маркера Incomplete. Код, сгенерированный cgo, будет использовать cgo.Incomplete для обозначения неполного типа C.

runtime/metrics

Go 1.20 добавляет новые поддерживаемые метрики, включая текущую настройку GOMAXPROCS (/sched/gomaxprocs:threads), количество выполненных вызовов cgo (/cgo/go-to-c-calls:calls), общее время блокировки мьютекса (/sync/mutex/wait/total:seconds) и различные меры времени, потраченного на сборку мусора.

Метрики гистограмм на основе времени теперь менее точны, но занимают гораздо меньше памяти.

runtime/pprof

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

Профили, собранные в Windows, теперь включают информацию о сопоставлении памяти, которая устраняет проблемы с символизацией для позиционно-независимых двоичных файлов.

runtime/trace

Фоновая очистка сборщика мусора теперь завершается реже, что приводит к меньшему количеству посторонних событий в трассировках выполнения.

strings

Новые функции CutPrefix и CutSuffix похожи на TrimPrefix и TrimSuffix, но также сообщают, была ли строка обрезана.

sync

Новые методы Map Swap, CompareAndSwap и CompareAndDelete позволяют автоматически обновлять существующие записи карты.

syscall

Во FreeBSD прокладки совместимости, необходимые для FreeBSD 11 и более ранних версий, были удалены.

В Linux определены дополнительные константы CLONE_* для использования с полем SysProcAttr.Cloneflags.

В Linux новые поля SysProcAttr.CgroupFD и SysProcAttr.UseCgroupFD позволяют поместить дочерний процесс в определенную контрольную группу.

testing

Новый метод B.Elapsed сообщает о текущем прошедшем времени эталонного теста, что может быть полезно для расчета показателей для отчета с помощью ReportMetric.

time

Новые константы макета времени DateTime, DateOnly и TimeOnly предоставляют имена для трех наиболее распространенных строк шаблона, используемых в обзоре общедоступного исходного кода Go.

Новый метод Time.Compare сравнивает два времени.

Parse теперь игнорирует точность менее наносекунды в своих входных данных, вместо того, чтобы сообщать об этих цифрах как об ошибке.

Метод Time.MarshalJSON теперь более строго соответствует RFC 3339.

unicode/utf16

Новая функция AppendRune добавляет кодировку UTF-16 данной руны к фрагменту uint16, аналогично utf8.AppendRune.


Читайте также:


четверг, 22 сентября 2022 г.

Релиз Go 1.19

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

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

Есть только одно небольшое изменение в языке, очень небольшое исправление области действия параметров типа в объявлениях методов. Существующие программы не затрагиваются.

Модель памяти

Модель памяти Go была пересмотрена, чтобы привести Go в соответствие с моделью памяти, используемой в C, C++, Java, JavaScript, Rust и Swift. Go предоставляет только последовательно согласованные атомарные элементы, а не какие-либо более простые формы, встречающиеся в других языках. Наряду с обновлением модели памяти в Go 1.19 представлены новые типы в пакете sync/atomic, которые упрощают использование атомарных значений, таких как atomic.Int64 и atomic.Pointer[T].

Порты

64-битная версия LoongArch

Go 1.19 добавляет поддержку 64-битной архитектуры Loongson LoongArch для Linux (GOOS=linux, GOARCH=loong64). Реализованный ABI — LP64D. Минимальная поддерживаемая версия ядра — 5.19.

Обратите внимание, что большинство существующих коммерческих дистрибутивов Linux для LoongArch поставляются со старыми ядрами с исторически несовместимым системным вызовом ABI. Скомпилированные двоичные файлы не будут работать в этих системах, даже если они статически связаны. Пользователи таких неподдерживаемых систем ограничены пакетом Go из дистрибутива.

RISC-V

Порт riscv64 теперь поддерживает передачу аргументов функции и результата с использованием регистров. Сравнительный анализ показывает типичное повышение производительности на 10% и более на riscv64.

Инструменты

Комментарии к документу

В Go 1.19 добавлена поддержка ссылок, списков и более четких заголовков в комментариях к документам. В рамках этого изменения gofmt теперь переформатирует комментарии к документам, чтобы сделать их отображаемый смысл более ясным.В качестве еще одной части этого изменения новый пакет go/doc/comment обеспечивает синтаксический анализ и переформатирование комментариев к документам, а также поддержку их преобразования в HTML, Markdown и текст.

Новое ограничение сборки unix

Unix-ограничение сборки теперь распознается в строках //go:build. Ограничение выполняется, если целевая операционная система, также известная как GOOS, является Unix или Unix-подобной системой. Для версии 1.19 допустимо, если GOOS является одним из следующих: aix, android, darwin, dragonfly, freebsd, hurd, illumos, ios, linux, netbsd, openbsd или solaris. В будущих релизах ограничение unix может соответствовать дополнительным вновь поддерживаемым операционным системам.

Команда go

Флаг -trimpath, если он установлен, теперь включается в настройки сборки, проставленные в двоичных файлах Go командой go build, и может быть проверен с помощью go version -m или debug.ReadBuildInfo.

go generate теперь устанавливает переменную среды GOROOT явно в среде генератора, так что генераторы могут найти правильный GOROOT, даже если он собран с -trimpath.

go test и go generate теперь размещает GOROOT/bin в начало PATH, используемого для подпроцесса, поэтому тесты и генераторы, выполняющие команду go, разрешат ее в один и тот же GOROOT.

go env теперь заключает в кавычки записи, содержащие пробелы в отчетных переменных CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS, CGO_LDFLAGS и GOGCCFLAGS.

go list -json теперь принимает список полей JSON, разделенных запятыми, для заполнения. Если указан список, выходные данные JSON будут включать только эти поля, и список перехода может избежать работы по вычислению полей, которые не включены. В некоторых случаях это может подавить ошибки, о которых в противном случае сообщалось бы.

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

Ветеринар (Vet)

vet чекер "errorsas" теперь сообщает когда errors.As вызывается со вторым аргументом типа *error, что является распространенной ошибкой.

Среда выполнения (Runtime)

Среда выполнения теперь включает поддержку мягкого ограничения памяти. Это ограничение памяти включает кучу (heap) Go и всю другую память, управляемую средой выполнения, и исключает внешние источники памяти, такие как сопоставления самого двоичного файла, память, управляемую на других языках, и память, удерживаемую операционной системой от имени программы Go. Этим ограничением можно управлять с помощью runtime/debug.SetMemoryLimit или эквивалентной переменной среды GOMEMLIMIT. Ограничение работает в сочетании с runtime/debug.SetGCPercent / GOGC и будет соблюдаться, даже если GOGC=off, позволяя программам Go всегда максимально использовать свой лимит памяти, в некоторых случаях повышая эффективность использования ресурсов. Обратите внимание, что небольшие ограничения памяти, порядка десятков мегабайт или меньше, с меньшей вероятностью будут соблюдаться из-за внешних факторов задержки, таких как планирование ОС. Большие пределы памяти, порядка сотен мегабайт и более, стабильны и готовы к работе.

Чтобы ограничить последствия перегрузки GC, когда размер динамической кучи программы приближается к пределу программной памяти, среда выполнения Go также пытается ограничить общее использование ЦП GC до 50%, исключая время простоя, предпочитая использовать больше памяти, а не предотвращая выполнение приложения. На практике ожидается, что это ограничение будет играть роль только в исключительных случаях, и новая метрика среды выполнения /gc/limiter/last-enabled:gc-cycle сообщает, когда это произошло в последний раз.

Среда выполнения теперь планирует намного меньше рабочих горутин GC в бездействующих потоках операционной системы, когда приложение простаивает достаточно, чтобы вызвать периодический цикл GC.

Среда выполнения теперь будет выделять начальные стеки горутин на основе исторического среднего использования стека горутин. Это позволяет избежать некоторого раннего роста стека и копирования, необходимого в среднем случае, в обмен на не более чем двукратное неиспользованное пространство на горутинах ниже среднего.

В операционных системах Unix программы Go, которые импортируют пакет os, теперь автоматически увеличивают лимит открытых файлов (RLIMIT_NOFILE) до максимально допустимого значения; то есть они изменяют мягкое ограничение, чтобы оно соответствовало жесткому ограничению. Это исправляет искусственно заниженные ограничения, установленные в некоторых системах для совместимости с очень старыми программами на C, использующими системный вызов select. Это ограничение не помогает программам Go, и вместо этого даже простые программы, такие как gofmt, часто не имеют файловых дескрипторов в таких системах при параллельной обработке большого количества файлов. Одним из последствий этого изменения является то, что программы Go, которые, в свою очередь, выполняют очень старые программы C в дочерних процессах, могут запускать эти программы со слишком высоким ограничением. Это можно исправить, установив жесткое ограничение перед вызовом программы Go.

Неисправимые фатальные ошибки (такие как одновременная запись карты или разблокировка разблокированных мьютексов) теперь печатают более простую трассировку, исключая метаданные времени выполнения (эквивалент фатальной паники), если только GOTRACEBACK не установлено значение system или crash. Внутренние трассировки неустранимых ошибок во время выполнения всегда включают полные метаданные независимо от значения GOTRACEBACK.

В ARM64 была добавлена ​​поддержка вызовов функций, введенных отладчиком, что позволяет пользователям вызывать функции из своего двоичного файла в интерактивном сеансе отладки при использовании отладчика, обновленного для использования этой функции.

Поддержка очистки адресов, добавленная в Go 1.18, теперь более точно обрабатывает аргументы функций и глобальные переменные.

Компилятор

Теперь компилятор использует таблицу переходов для реализации больших целочисленных и строковых операторов переключения. Улучшения производительности оператора switch различаются, но могут быть на порядка 20% быстрее. (только GOARCH=amd64 и GOARCH=arm64)

Компилятору Go теперь требуется флаг -p=importpath для создания связываемого объектного файла. Это уже предоставлено командой go и Bazel. Любые другие системы сборки, которые напрямую вызывают компилятор Go, также должны убедиться, что они передают этот флаг.

Компилятор Go больше не поддерживает флаг -importmap. Системы сборки, которые напрямую вызывают компилятор Go, должны вместо этого использовать флаг -importcfg.

Ассемблер

Как и компилятору, ассемблеру теперь требуется флаг -p=importpath для создания компоновочного объектного файла. Это уже предоставлено командой go. Любые другие системы сборки, которые напрямую вызывают ассемблер Go, также должны убедиться, что они передают этот флаг.

Линкер

На платформах ELF компоновщик теперь создает сжатые разделы DWARF в стандартном формате gABI (SHF_COMPRESSED) вместо устаревшего формата .zdebug.

Основная библиотека

Новые атомарные типы

Пакет sync/atomic определяет новые атомарные типы Bool, Int32, Int64, Uint32, Uint64, Uintptr и Pointer. Эти типы скрывают базовые значения, поэтому все обращения вынуждены использовать атомарные API. Pointer также избавляет от необходимости конвертировать в unsafe.Pointer в местах вызовов. Int64 и Uint64 автоматически выравниваются по 64-битным границам в структурах и выделенных данных даже в 32-битных системах.

PATH поиск

Command и LookPath больше не позволяют находить результаты поиска PATH относительно текущего каталога. Это устраняет общий источник проблем с безопасностью, но может также нарушить работу существующих программ, которые зависят от использования, скажем, exec.Command("prog") для запуска двоичного файла с именем prog (или, в Windows, prog.exe) в текущем каталоге.

В Windows Command и LookPath теперь учитывают переменную среды NoDefaultCurrentDirectoryInExePath, что позволяет отключить неявный поиск “.” по умолчанию в поиске PATH в системах Windows.

Мелкие изменения в библиотеке

Как всегда, в библиотеку внесены различные незначительные изменения и обновления, сделанные с учетом обещания совместимости с Go 1. Существуют также различные улучшения производительности, не перечисленные здесь.

archive/zip

Reader теперь игнорирует данные, отличные от ZIP, в начале ZIP-файла, что соответствует большинству других реализаций. Это необходимо, помимо прочего, для чтения некоторых файлов Java JAR.

crypto/elliptic

Работа с недопустимыми точками кривой (теми, для которых метод IsOnCurve возвращает false и которые никогда не возвращаются Unmarshal или методом Curve, работающим с допустимой точкой) всегда было неопределенным поведением и может привести к атакам восстановления ключа. Если для Marshal, MarshalCompressed, Add, Double или ScalarMult указана недопустимая точка, они теперь будут паниковать.

Операции ScalarBaseMult с кривыми P224, P384 и P521 теперь выполняются до трех раз быстрее, что приводит к аналогичному ускорению некоторых операций ECDSA. Общая (не оптимизированная для платформы) реализация P256 была заменена реализацией, полученной из официально проверенной модели; это может привести к значительному замедлению работы на 32-разрядных платформах.

crypto/rand

Read больше не буферизует случайные данные, полученные от операционной системы, между вызовами. Приложения, которые выполняют много небольших операций чтения с высокой частотой, могут по соображениям производительности обернуть Reader в bufio.Reader, стараясь использовать io.ReadFull, чтобы гарантировать отсутствие частичных чтений.

В Plan 9 функция Read была повторно реализована, заменив алгоритм ANSI X9.31 на генератор быстрого стирания ключей.

Реализация Prime была изменена, чтобы использовать только выборку отклонения, что устраняет предвзятость при создании небольших простых чисел в некриптографических контекстах, устраняет одну возможную незначительную утечку времени и лучше согласовывает поведение с BoringSSL, при этом упрощая реализацию. Это изменение создает разные выходные данные для данного случайного исходного потока по сравнению с предыдущей реализацией, что может нарушить тесты, написанные с ожиданием определенных результатов от определенных детерминированных случайных источников. Чтобы предотвратить такие проблемы в будущем, реализация теперь преднамеренно недетерминирована по отношению к входному потоку.

crypto/tls

Опция GODEBUG tls10default=1 удалена. По-прежнему можно включить TLS 1.0 на стороне клиента, установив Config.MinVersion.

Сервер и клиент TLS теперь отклоняют повторяющиеся расширения в рукопожатиях TLS, как того требуют RFC 5246, раздел 7.4.1.4 и RFC 8446, раздел 4.2.

crypto/x509

CreateCertificate больше не поддерживает создание сертификатов с SignatureAlgorithm, для которого задано значение MD5WithRSA.

CreateCertificate больше не принимает отрицательные серийные номера.

CreateCertificate больше не будет выдавать пустую SEQUENCE, если созданный сертификат не имеет расширений.

Удаление GODEBUG optionx509sha1=1, первоначально запланированное для Go 1.19, было перенесено на будущий релиз. Приложения, использующие его, должны работать при миграции. Практические атаки на SHA-1 были продемонстрированы с 2017 года, а общедоступные доверенные центры сертификации не выпускали сертификаты SHA-1 с 2015 года.

ParseCertificate и ParseCertificateRequest теперь отклоняют сертификаты и CSR, которые содержат повторяющиеся расширения.

Новые методы CertPool.Clone и CertPool.Equal позволяют клонировать CertPool и проверять эквивалентность двух CertPools соответственно.

Новая функция ParseRevocationList обеспечивает более быстрый и безопасный анализатор CRL, который возвращает RevocationList. При разборе CRL также заполняются новые поля RevocationList RawIssuer, Signature, AuthorityKeyId и Extensions, которые игнорируются CreateRevocationList.

Новый метод RevocationList.CheckSignatureFrom проверяет, является ли подпись в CRL действительной подписью сертификата.

Функции ParseCRL и ParseDERCRL теперь объявлены устаревшими в пользу ParseRevocationList. Метод Certificate.CheckCRLSignature устарел в пользу RevocationList.CheckSignatureFrom.

Построитель пути Certificate.Verify был переработан и теперь должен создавать более качественные цепочки и/или быть более эффективным в сложных сценариях. Ограничения имен теперь также применяются к неконечным сертификатам.

crypto/x509/pkix

Типы CertificateList и TBSCertificateList устарели. Вместо этого следует использовать новую функциональность crypto/x509 CRL.

debug/elf

Новые константы EM_LOONGARCH и R_LARCH_* поддерживают порт loong64.

debug/pe

Новый метод File.COFFSymbolReadSectionDefAux, возвращающий COFFSymbolAuxFormat5, обеспечивает доступ к информации COMDAT в разделах PE-файла. Они поддерживаются новыми константами IMAGE_COMDAT_* и IMAGE_SCN_*.

encoding/binary

Новый интерфейс AppendByteOrder предоставляет эффективные методы добавления uint16, uint32 или uint64 к срезу байтов. BigEndian и LittleEndian теперь реализуют этот интерфейс.

Точно так же новые функции AppendUvarint и AppendVarint являются эффективными версиями добавления функций PutUvarint и PutVarint.

encoding/csv

Новый метод Reader.InputOffset сообщает о текущей позиции ввода средства чтения в виде смещения в байтах, аналогично Decoder.InputOffset в encoding/json.

encoding/xml

Новый метод Decoder.InputPos сообщает текущую позицию ввода считывателя в виде строки и столбца, аналогично Decoder.FieldPos из encoding/csv.

flag

Новая функция TextVar определяет флаг со значением, реализующим encoding.TextUnmarshaler, что позволяет переменным флага командной строки иметь такие типы, как big.Int, netip.Addr и time.Time.

fmt

Новые функции Append, Appendf и Appendln добавляют отформатированные данные в байтовые срезы.

go/parser

Синтаксический анализатор теперь распознает ~x как унарное выражение с оператором token.TILDE, что позволяет лучше устранять ошибки, когда ограничение типа, такое как ~int, используется в неправильном контексте.

go/types

Новые методы Func.Origin и Var.Origin возвращают соответствующий Object универсального типа для синтетических объектов Func и Var, созданных во время создания экземпляра типа.

Больше невозможно создавать бесконечное количество различных, но идентичных экземпляров именованного типа с помощью рекурсивных вызовов Named.Underlying или Named.Method.

hash/maphash

Новые функции Bytes и String обеспечивают эффективный способ хеширования одного байтового среза или строки. Они эквивалентны использованию более общего хэша с одной записью, но позволяют избежать накладных расходов на настройку для небольших входных данных.

html/template

Тип FuncMap теперь является псевдонимом для FuncMap пакета text/template вместо собственного именованного типа. Это позволяет писать код, который работает с FuncMap при любых настройках.

image/draw

Рисование с оператором Src сохраняет цвета без предварительного умножения альфа-канала, когда целевое и исходное изображения оба имеют формат image.NRGBA или оба изображения image.NRGBA64. Это отменяет изменение поведения, случайно внесенное оптимизацией библиотеки Go 1.18; код теперь соответствует поведению в Go 1.17 и более ранних версиях.

io

Результат NopCloser теперь реализует WriterTo всякий раз, когда это происходит на входе.

Результат MultiReader теперь безоговорочно реализует WriterTo. Если какое-либо базовое средство чтения не реализует WriterTo, оно моделируется соответствующим образом.

mime

Только в Windows пакет mime теперь игнорирует запись реестра о том, что расширение .js должно иметь тип MIME text/plain. Это распространенная непреднамеренная неправильная настройка в системах Windows. В результате .js будет иметь тип MIME text/javascript по умолчанию; кодировка=utf-8. Приложения, которые ожидают text/plain в Windows, теперь должны явно вызывать AddExtensionType.

net

Чистый преобразователь Go теперь будет использовать EDNS(0) для включения рекомендуемой максимальной длины ответного пакета, что позволяет ответным пакетам содержать до 1232 байт (ранее максимальное значение составляло 512). В том маловероятном случае, если это вызовет проблемы с локальным распознавателем DNS, установка переменной среды GODEBUG=netdns=cgo для использования распознавателя на основе cgo должна работать.

Когда функция или метод пакета net возвращает ошибку "I/O timeout", эта ошибка теперь будет удовлетворять errors.Is(err, context.DeadlineExceeded). Когда функция пакета net возвращает ошибку "operation was canceled" ("операция была отменена"), эта ошибка теперь удовлетворяет errors.Is(err, context.Canceled). Эти изменения предназначены для того, чтобы упростить тестирование кода в случаях, когда отмена контекста или таймаут приводят к тому, что функция или метод пакета net возвращает ошибку, сохраняя при этом обратную совместимость для сообщений об ошибках.

Resolver.PreferGo теперь реализован в Windows и Plan 9. Ранее он работал только на платформах Unix. В сочетании с Dialer.Resolver и Resolver.Dial теперь можно писать переносимые программы и контролировать все поиски DNS-имен при подключении.

Пакет net теперь имеет начальную поддержку тега сборки netgo в Windows. При использовании пакет использует DNS-клиент Go (используемый Resolver.PreferGo) вместо того, чтобы запрашивать у Windows результаты DNS. Однако вышестоящий DNS-сервер, который он обнаруживает из Windows, может быть еще неправильным со сложными системными сетевыми конфигурациями.

net/http

ResponseWriter.WriteHeader теперь поддерживает отправку определяемых пользователем информационных заголовков 1xx.

io.ReadCloser, возвращаемый MaxBytesReader, теперь будет возвращать определенный тип ошибки MaxBytesError при превышении предела чтения.

HTTP-клиент будет обрабатывать ответ 3xx без заголовка Location, возвращая его вызывающей стороне, а не рассматривая его как ошибку.

net/url

Новая функция JoinPath и метод URL.JoinPath создают новый URL-адрес путем присоединения к списку элементов пути.

Тип URL-адреса теперь различает URL-адреса без полномочий и URL-адреса с пустыми полномочиями. Например, http:///path имеет пустые права доступа (хост), а в http:/path их нет.

Новое поле URL-адреса OmitHost имеет значение true, если URL-адрес имеет пустые полномочия.

os/exec

Cmd с непустым полем Dir и nil Env теперь неявно устанавливает переменную среды PWD для подпроцесса в соответствие с Dir.

Новый метод Cmd.Environ сообщает о среде, которая будет использоваться для запуска команды, включая неявно заданную переменную PWD.

reflect

Метод Value.Bytes теперь принимает адресные массивы в дополнение к срезам.

Методы Value.Len и Value.Cap теперь успешно работают с указателем на массив и возвращают длину этого массива, чтобы соответствовать тому, что делают встроенные функции len и cap.

regexp/syntax

Go 1.18 релиз-кандидат 1, Go 1.17.8 и Go 1.16.15 включали исправление безопасности для синтаксического анализатора регулярных выражений, заставляющее его отклонять очень глубоко вложенные выражения. Поскольку релизы исправлений Go не вводят новый API, синтаксический анализатор в этом случае вернул синтаксис.ErrInternalError. В Go 1.19 добавлена ​​более конкретная ошибка синтаксис.ErrNestingDepth, которую теперь возвращает синтаксический анализатор.

runtime

Функция GOROOT теперь возвращает пустую строку (вместо "go"), когда бинарный файл был собран с установленным флагом -trimpath и переменная GOROOT не установлена в среде процесса.

runtime/metrics

Новая метрика /sched/gomaxprocs:threads сообщает о текущем значении runtime.GOMAXPROCS.

Новая метрика /cgo/go-to-c-calls:calls сообщает об общем количестве вызовов, сделанных с Go на C. Эта метрика идентична функции runtime.NumCgoCall.

Новая метрика /gc/limiter/last-enabled:gc-cycle сообщает о последнем цикле сборки мусора, когда был включен ограничитель ЦП сборщика мусора.

runtime/pprof

Время пауз Stop-the-world было значительно сокращено при сборе профилей goroutine, что уменьшило общее влияние задержки на приложение.

MaxRSS теперь сообщается в профилях кучи для всех операционных систем Unix (ранее сообщалось только для GOOS=android, darwin, ios и linux).

runtime/race

Детектор гонок был обновлен для использования санитайзера потоков версии v3 на всех поддерживаемых платформах, кроме windows/amd64 и openbsd/amd64, которые остаются на версии v2. По сравнению с v2, теперь он обычно в 1,5–2 раза быстрее, использует вдвое меньше памяти и поддерживает неограниченное количество горутин. В Linux детектор гонки теперь требует как минимум glibc версии 2.17 и GNU binutils 2.26.

Детектор гонки теперь поддерживается на GOARCH=s390x.

Поддержка детектора гонки для openbsd/amd64 была удалена из вышестоящего санитайзера потоков, поэтому вряд ли оно когда-либо будет обновлено с версии v2.

runtime/trace

Если трассировка и профилировщик ЦП включены одновременно, трассировка выполнения включает образцы профиля ЦП как мгновенные события.

sort

Алгоритм сортировки был переписан для использования быстрой сортировки без шаблонов, которая работает быстрее в некоторых распространенных сценариях.

Новая функция Find похожа на Search, но часто проще в использовании: она возвращает дополнительное логическое значение, сообщающее, найдено ли равное значение.

strconv

Quote и связанные с ней функции теперь указывают руну U+007F как \x7f, а не \u007f, для совместимости с другими значениями ASCII.

syscall

На PowerPC (GOARCH=ppc64, ppc64le) Syscall, Syscall6, RawSyscall и RawSyscall6 теперь всегда возвращают 0 для возвращаемого значения r2 вместо неопределенного значения.

В AIX и Solaris теперь определен Getrusage.

time

Новый метод Duration.Abs предоставляет удобный и безопасный способ получения абсолютного значения длительности путем преобразования −2⁶³ в 2⁶³−1. (Этот пограничный случай может произойти в результате вычитания недавнего времени из нулевого времени.)

Новый метод Time.ZoneBounds возвращает время начала и окончания часового пояса, действующего в данный момент времени. Его можно использовать в цикле для перечисления всех известных переходов часовых поясов в заданном месте.


Читайте также: