Примечания к выпуску 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.
Размер двоичных файлов и взаимодействие с другими языками пока не были приоритетом, но могут быть решены в будущих релизах.
В результате добавления нового значения GOOS “js” и значения GOARCH “wasm”, файлы Go с именами *_js.go или *_wasm.go теперь будут
игнорироваться инструментами Go, кроме случаев, когда используются соответствующие значения GOOS/GOARCH.
Если у вас есть существующие файлы, соответствующие этим шаблонам, их необходимо переименовать.
Больше информации можно найти на странице вики WebAssembly.
Зарезервированные значения GOARCH для RISC-V
Основной компилятор Go пока не поддерживает архитектуру RISC-V
но мы зарезервировали значения GOARCH
“riscv” и “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) принимались при ожидании названия часового пояса.