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

Введение в Go 1.11

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

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

В спецификации языка не было внесено никаких изменений.

Платформы

Как было объявлено в примечаниях к выпуску Go 1.10, Go 1.11 теперь требует OpenBSD 6.2 или более поздней версии, macOS 10.10 Yosemite или более поздней версии, или Windows 7 или более поздней версии; поддержка предыдущих версий этих операционных систем была удалена.

Go 1.11 поддерживает предстоящий выпуск OpenBSD 6.4. Из-за изменений в ядре OpenBSD, более старые версии Go не будут работать на OpenBSD 6.4.

Существуют известные проблемы с NetBSD на оборудовании i386.

Детектор гонок теперь поддерживается на linux/ppc64le и, в меньшей степени, на netbsd/amd64. Поддержка детектора гонок в NetBSD имеет известные проблемы.

Санитайзер памяти (-msan) теперь поддерживается на linux/arm64.

Режимы сборки c-shared и c-archive теперь поддерживаются на freebsd/amd64.

На 64-битных системах MIPS новые параметры переменных среды GOMIPS64=hardfloat (по умолчанию) и GOMIPS64=softfloat позволяют выбрать использование аппаратных инструкций или программной эмуляции для вычислений с плавающей точкой. Для 32-битных систем переменная среды по-прежнему называется GOMIPS, как было добавлено в Go 1.10.

На ARM-системах с программной плавающей точкой (GOARM=5), Go теперь использует более эффективный программный интерфейс плавающей точки. Это прозрачно для кода на Go, но ARM-ассемблер, использующий инструкции плавающей точки без защиты на GOARM, прекратит работать и должен быть перенесен на новый интерфейс.

Go 1.11 на ARMv7 больше не требует ядра Linux, настроенного с KUSER_HELPERS. Этот параметр включен в стандартные конфигурации ядра, но иногда отключается в урезанных конфигурациях.

WebAssembly

Go 1.11 добавляет экспериментальную поддержку WebAssembly (js/wasm).

Программы на Go в настоящее время компилируются в один WebAssembly-модуль, который включает в себя среду выполнения Go для планирования горутин, сборки мусора, карт и т. д. В результате размер полученного файла составляет минимум около 2 МБ или 500 КБ при сжатии. Программы на Go могут вызывать JavaScript с использованием нового экспериментального пакета syscall/js. Размер двоичных файлов и взаимодействие с другими языками пока не были приоритетом, но могут быть решены в будущих релизах.

В результате добавления нового значения GOOSjs” и значения GOARCHwasm”, файлы Go с именами *_js.go или *_wasm.go теперь будут игнорироваться инструментами Go, кроме случаев, когда используются соответствующие значения GOOS/GOARCH. Если у вас есть существующие файлы, соответствующие этим шаблонам, их необходимо переименовать.

Больше информации можно найти на странице вики WebAssembly.

Зарезервированные значения GOARCH для RISC-V

Основной компилятор Go пока не поддерживает архитектуру RISC-V но мы зарезервировали значения GOARCHriscv” и “riscv64”, используемые в Gccgo, который поддерживает RISC-V. Это означает, что файлы Go с именами *_riscv.go теперь также будут игнорироваться инструментами Go, кроме случаев, когда используются соответствующие значения GOOS/GOARCH.

Инструменты

Модули, версионирование пакетов и управление зависимостями

Go 1.11 добавляет предварительную поддержку нового понятия, называемого «модулями», альтернативы GOPATH с встроенной поддержкой версионирования и распространения пакетов. Используя модули, разработчики больше не ограничены работой внутри GOPATH, информация о зависимостях версий становится явной, но при этом легковесной, а сборки становятся более надежными и воспроизводимыми.

Поддержка модулей считается экспериментальной. Детали могут измениться в ответ на обратную связь от пользователей Go 1.11, и у нас есть еще больше инструментов, которые планируется добавить. Хотя детали поддержки модулей могут измениться, проекты, которые перешли на модули с использованием Go 1.11, продолжат работать с Go 1.12 и более поздними версиями. Если вы столкнетесь с ошибками при использовании модулей, пожалуйста, сообщите о них, чтобы мы могли исправить их. За дополнительной информацией обращайтесь к документации команды go.

Ограничения пути импорта

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

Загрузка пакетов

Новый пакет golang.org/x/tools/go/packages предоставляет простой API для поиска и загрузки пакетов исходного кода Go. Несмотря на то, что он ещё не входит в стандартную библиотеку, для многих задач он эффективно заменяет пакет go/build, API которого не может полностью поддерживать модули. Поскольку он запускает внешнюю команду запроса, такую как go list, для получения информации о пакетах Go, он позволяет создавать инструменты анализа, которые работают одинаково хорошо с альтернативными системами сборки, такими как Bazel и Buck.

Требование к кэшу сборки

Go 1.11 будет последним релизом, поддерживающим установку переменной окружения GOCACHE=off для отключения кэша сборки, введённого в Go 1.10. Начиная с Go 1.12 кэш сборки будет обязателен, как шаг к устранению $GOPATH/pkg. Поддержка модулей и загрузки пакетов, описанная выше, уже требует включения кэша сборки. Если вы отключили кэш сборки из-за возникших проблем, пожалуйста, сообщите об этом, чтобы мы узнали о них.

Инструментарий компилятора

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

Инструментарий компилятора теперь поддерживает информацию о столбцах в директивах строк.

Введён новый формат данных экспорта пакета. Это должно быть прозрачно для конечных пользователей, кроме ускорения времени сборки для больших проектов на Go. Если это вызывает проблемы, его можно снова отключить, передав -gcflags=all=-iexport=false в инструмент go при сборке двоичного файла.

Компилятор теперь отклоняет неиспользуемые переменные, объявленные в условиях типа переключателя (type switch guard), например, x в следующем примере:

<code>func f(v interface{}) {
  switch x := v.(type) {
  }
}
</code>

Это уже отклонялось как gccgo, так и go/types.

Ассемблер

Ассемблер для amd64 теперь принимает инструкции AVX512.

Отладка

Компилятор теперь создаёт значительно более точную отладочную информацию для оптимизированных двоичных файлов, включая информацию о местоположении переменных, номера строк и точки останова. Это должно позволить отлаживать двоичные файлы, скомпилированные без -N и -l. Однако все ещё существуют ограничения в качестве отладочной информации, некоторые из которых являются фундаментальными, а другие будут продолжать улучшаться в будущих релизах.

Разделы DWARF теперь сжимаются по умолчанию благодаря расширенной и более точной отладочной информации, производимой компилятором. Это прозрачно для большинства ELF-инструментов (таких как отладчики в Linux и *BSD), и поддерживается отладчиком Delve на всех платформах, но имеет ограниченную поддержку в нативных инструментах macOS и Windows. Чтобы отключить сжатие DWARF, передайте -ldflags=-compressdwarf=false в инструмент go при сборке двоичного файла.

Go 1.11 добавляет экспериментальную поддержку вызова функций Go внутри отладчика. Это полезно, например, для вызова методов String при остановке на точке останова. На данный момент поддерживается только Delve (версия 1.1.0 и выше).

Test

Начиная с Go 1.10, команда go test запускает go vet на тестируемом пакете, чтобы выявить проблемы до запуска теста. Поскольку vet типизирует код с помощью go/types перед запуском, тесты, которые не проходят проверку типов, теперь будут завершаться с ошибкой. В частности, тесты, содержащие неиспользуемую переменную внутри замыкания, скомпилированного с помощью Go 1.10, потому что компилятор Go некорректно принимал их (Issue #3059), но теперь будут завершаться с ошибкой, поскольку go/types корректно сообщает об ошибке "unused variable" в этом случае.

Флаг -memprofile для go test теперь по умолчанию использует профиль "allocs", который записывает общее количество байт, выделенных с момента начала теста (включая освобождённые байты).

Vet

Команда go vet теперь сообщает фатальную ошибку, когда пакет под анализом не проходит проверку типов. Ранее ошибка типизации просто вызывала предупреждение и приводила к завершению vet со статусом 1.

Кроме того, go vet стал более надежным при проверке форматирования обёрток printf. Теперь Vet выявляет ошибку в следующем примере:

<code>func wrapper(s string, args ...interface{}) {
  fmt.Printf(s, args...)
}

func main() {
  wrapper("%s", 42)
}
</code>

Trace

С новым runtime/trace пакетом и его API для аннотаций пользователем, пользователи могут записывать информацию на уровне приложения в трассировки выполнения и создавать группы связанных горутин. Команда go tool trace визуализирует эту информацию в представлении трассировки и на новой странице анализа пользовательских задач/регионов.

Cgo

Начиная с Go 1.10, cgo переводит некоторые типы указателей C в тип Go uintptr. Эти типы включают иерархию CFTypeRef в фреймворке CoreFoundation Darwin и иерархию jobject в интерфейсе JNI Java. В Go 1.11 были внесены несколько улучшений в код, обнаруживающий эти типы. Код, использующий эти типы, может потребовать обновления. См. примечания к выпуску Go 1.10 для подробностей.

Команда Go

Переменная окружения GOFLAGS теперь может использоваться для установки флагов по умолчанию для команды go. Это полезно в определенных ситуациях. Связывание может быть заметно медленнее на слабых системах из-за DWARF, и пользователи могут захотеть устанавливать -ldflags=-w по умолчанию. Для модулей некоторые пользователи и системы CI захотят использовать vendoring всегда, поэтому они должны устанавливать -mod=vendor по умолчанию. За дополнительной информацией обращайтесь к документации команды go.

Godoc

Go 1.11 будет последним релизом, поддерживающим командный интерфейс godoc. В будущих релизах godoc будет работать только как веб-сервер. Пользователям следует использовать команду go doc для получения справки в командной строке.

Веб-сервер godoc теперь показывает, какая версия Go ввела новые API-функции. Начальная версия Go для типов, функций и методов отображается выровненно по правому краю. Например, смотрите UserCacheDir, с «1.11» справа. Для полей структур добавляются комментарии в строке, если поле было добавлено в версии Go, отличной от той, в которой был введён сам тип. Пример поля структуры можно посмотреть в ClientTrace.Got1xxResponse.

Gofmt

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

Обратите внимание, что подобные незначительные обновления gofmt ожидаются время от времени. В общем случае, системы, которым требуется согласованное форматирование исходного кода Go, должны использовать конкретную версию двоичного файла gofmt. За дополнительной информацией обращайтесь к документации пакета go/format.

Run

Команда go run теперь позволяет указывать один путь импорта, имя каталога или шаблон, соответствующий одному пакету. Это позволяет использовать go run pkg или go run dir, и, в частности, go run .

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

Среда выполнения теперь использует разреженную структуру кучи, поэтому больше нет ограничения по размеру кучи Go (ранее ограничение составляло 512 ГиБ). Это также устраняет редкие сбои из-за "конфликта адресного пространства" в смешанных Go/C бинарных файлах или бинарных файлах, скомпилированных с флагом -race.

В macOS и iOS среда выполнения теперь использует libSystem.dylib вместо прямых вызовов ядра. Это должно сделать бинарные файлы Go более совместимыми с будущими версиями macOS и iOS. Пакет syscall по-прежнему делает прямые системные вызовы; исправление этого планируется в будущем релизе.

Производительность

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

Также были внесены изменения в производительность пакета math/big, а также множество изменений по всему дереву, специфичных для GOARCH=arm64.

Инструментарий компилятора

Компилятор теперь оптимизирует операции очистки карт вида:

<code>for k := range m {
  delete(m, k)
}
</code>

Компилятор теперь оптимизирует расширение срезов вида append(s, make([]T, n)...).

Компилятор теперь выполняет гораздо более агрессивную оптимизацию проверок границ и удаление ветвлений. В частности, он теперь распознаёт транзитивные отношения, так что если i<j и j<len(s), то можно использовать эти факты для исключения проверки границ для s[i]. Компилятор также понимает простую арифметику, например, s[i-10], и может распознавать более сложные случаи в циклах. Более того, компилятор теперь использует информацию о границах для более агрессивной оптимизации операций сдвига.

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

Все изменения в стандартной библиотеке являются незначительными.

Незначительные изменения в библиотеке

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

crypto

Определённые криптографические операции, включая ecdsa.Sign, rsa.EncryptPKCS1v15 и rsa.GenerateKey, теперь случайным образом читают дополнительный байт случайности, чтобы гарантировать, что тесты не зависят от внутреннего поведения.

crypto/cipher

Новая функция NewGCMWithTagSize реализует режим счётчика Галуа (Galois Counter Mode) с нестандартной длиной тега для совместимости с существующими криптосистемами.

crypto/rsa

PublicKey теперь реализует метод Size, который возвращает размер модуля в байтах.

crypto/tls

Новый метод ExportKeyingMaterial типа ConnectionState позволяет экспортировать ключевые данные, привязанные к соединению, согласно RFC 5705.

crypto/x509

Устаревшее, legacy поведение, при котором поле CommonName рассматривалось как имя хоста, когда альтернативные имена субъекта отсутствуют, теперь отключено, если CN не является корректным именем хоста. Поле CommonName может быть полностью проигнорировано путем добавления экспериментального значения x509ignoreCN=1 в переменную окружения GODEBUG. Если CN игнорируется, сертификаты без альтернативных имен субъекта проходят проверку в цепочках с ограничениями имён, вместо того чтобы возвращать ошибку NameConstraintsWithoutSANs.

Ограничения расширенного использования ключа снова проверяются только в том случае, если они присутствуют в поле KeyUsages типа VerifyOptions, а не проверяются всегда. Это соответствует поведению Go 1.9 и более ранних версий.

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

debug/elf

Добавлены дополнительные константы ELFOSABI и EM.

encoding/asn1

Функции Marshal и Unmarshal теперь поддерживают аннотации «приватного» класса для полей.

encoding/base32

Декодер теперь последовательно возвращает io.ErrUnexpectedEOF для неполных частей. Ранее в некоторых случаях он возвращал io.EOF.

encoding/csv

Reader теперь отклоняет попытки установить поле Comma в символ двойных кавычек, поскольку символы двойных кавычек уже имеют специальное значение в CSV.

html/template

Пакет изменил своё поведение при передаче в неявную функцию экранирования значения типизированного интерфейса. Ранее такое значение записывалось как (экранированная форма) <nil>. Теперь такие значения игнорируются, точно так же, как не типизированное значение nil (и всегда было так).

image/gif

Теперь поддерживаются анимированные GIF-файлы без цикличности. Они обозначаются наличием LoopCount со значением -1.

io/ioutil

Функция TempFile теперь поддерживает указание местоположения случайных символов в имени файла. Если аргумент prefix содержит символ “*”, случайная строка заменяет “*”. Например, аргумент prefix со значением “myname.*.bat” приведет к созданию случайного имени файла вроде “myname.123456.bat”. Если символ “*” не указан, сохраняется прежнее поведение, и случайные цифры добавляются в конец.

math/big

ModInverse теперь возвращает nil, когда g и n не являются взаимно простыми. Ранее результат был неопределенным.

mime/multipart

Обработка данных формы с отсутствующими/пустыми именами файлов была восстановлена до поведения, которое было в Go 1.9: в Form для части данных формы значение доступно в поле Value, а не в поле File. В релизах Go 1.10 по 1.10.3 часть данных формы с отсутствующим/пустым именем файла и непустым полем “Content-Type” сохранялась в поле File. Это изменение было ошибкой в 1.10 и было отменено, чтобы вернуться к поведению 1.9.

mime/quotedprintable

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

net

Новый тип ListenConfig и новое поле Dialer.Control позволяют устанавливать параметры сокета до принятия и создания соединений соответственно.

Методы Read и Write типа syscall.RawConn теперь корректно работают в Windows.

Пакет net теперь автоматически использует splice системный вызов в Linux при копировании данных между TCP-соединениями в TCPConn.ReadFrom, как вызывается io.Copy. В результате достигается более быстрое и эффективное TCP-проксирование.

Методы TCPConn.File, UDPConn.File, UnixConn.File и IPConn.File больше не переводят возвращаемый *os.File в блокирующий режим.

net/http

Тип Transport имеет новую опцию MaxConnsPerHost, которая позволяет ограничивать максимальное количество подключений на хост.

Тип Cookie имеет новое поле SameSite (нового типа с тем же названием SameSite), чтобы представлять новую атрибут cookie, недавно поддерживаемую большинством браузеров. Transport из пакета net/http сам не использует атрибут SameSite, но пакет поддерживает его разбор и сериализацию для использования браузерами.

Больше не разрешается повторно использовать Server после вызова Shutdown или Close. Ранее это никогда официально не поддерживалось и часто приводило к неожиданному поведению. Теперь все последующие вызовы методов Serve сервера будут возвращать ошибки после завершения работы или закрытия.

Константа StatusMisdirectedRequest теперь определена для HTTP-статуса 421.

HTTP-сервер больше не отменяет контексты или отправляет данные в каналы CloseNotifier при получении пайплайновых HTTP/1.1-запросов. Браузеры не используют HTTP-пайплайниг, но некоторые клиенты (например, apt из Debian) могут быть настроены на его использование.

ProxyFromEnvironment, который используется DefaultTransport, теперь поддерживает запись в формате CIDR и порты в переменной окружения NO_PROXY.

net/http/httputil

ReverseProxy имеет новую опцию ErrorHandler, позволяющую изменять обработку ошибок.

ReverseProxy теперь также передаёт заголовки запросов “TE: trailers” в бэкенд, как этого требует протокол gRPC.

os

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

Новый ModeIrregular является битом типа FileMode, который обозначает, что файл не является обычным файлом, но ничего другого о нем неизвестно, или что это не сокет, устройство, именованный канал, символическая ссылка или другой тип файла, для которого Go имеет определённый бит режима.

Функция Symlink теперь работает для непривилегированных пользователей в Windows 10 на машинах с включённым режимом Разработчика.

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

os/signal

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

os/user

Пакет os/user теперь может быть собран в чистом Go режиме с использованием тега сборки “osusergo”, независимо от установки переменной окружения CGO_ENABLED=0. Ранее единственным способом использовать чистую Go реализацию пакета было отключение поддержки cgo для всего приложения.

runtime

Установка переменной окружения GODEBUG=tracebackancestors=N теперь расширяет трассировки стека с указанием стеков, в которых были созданы горутины, где N ограничивает количество родительских горутин, которые будут отображаться.

runtime/pprof

В этом выпуске добавлен новый тип профиля "allocs", который профилирует общее количество байт, выделенных с момента запуска программы (включая байты, подлежащие сборке мусора). Это идентично существующему профилю "heap", просматриваемому в режиме -alloc_space. Теперь go test -memprofile=... выводит профиль "allocs" вместо профиля "heap".

sync

Профиль мьютекса теперь включает контекст чтения/записи для RWMutex. Контекст записи/записи уже был включен в профиль мьютекса.

syscall

В Windows несколько полей были изменены с uintptr на новый Pointer тип, чтобы избежать проблем с garbage collector Go. Те же изменения были внесены в пакет golang.org/x/sys/windows. Для любого затронутого кода пользователи должны сначала перейти с пакета syscall на пакет golang.org/x/sys/windows, а затем изменить использование на Pointer, соблюдая правила преобразования unsafe.Pointer.

В Linux параметр flags функции Faccessat теперь реализован так же, как в glibc. В более ранних версиях Go параметр flags игнорировался.

В Linux параметр flags функции Fchmodat теперь проверяется. В Linux fchmodat не поддерживает параметр flags, поэтому теперь мы имитируем поведение glibc и возвращаем ошибку, если он не равен нулю.

text/scanner

Метод Scanner.Scan теперь возвращает токен RawString вместо String для литералов сырых строк.

text/template

Изменение переменных шаблона с помощью присваиваний теперь разрешено с использованием токена =:

<code>  {{ $v := "init" }}
{{ if true }}
{{ $v = "changed" }}
{{ end }}
v: {{ $v }} {{/* "changed" */}}
</code>

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

time

Парсинг часовых поясов, обозначенных знаком и смещением, теперь поддерживается. В предыдущих версиях числовые названия часовых поясов (например, +03) не считались допустимыми, и только трехбуквенные аббревиатуры (например, MST) принимались при ожидании названия часового пояса.

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

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