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

Введение в Go 1.12

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

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

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

Платформы

Детектор гонок теперь поддерживается на linux/arm64.

Go 1.12 — последний выпуск, который поддерживается на FreeBSD 10.x, который уже достиг конца срока поддержки. Go 1.13 будет требовать FreeBSD 11.2+ или FreeBSD 12.0+. FreeBSD 12.0+ требует ядро с включённой опцией COMPAT_FREEBSD11 (по умолчанию она включена).

cgo теперь поддерживается на linux/ppc64.

hurd теперь является допустимым значением для GOOS, зарезервированным для системы GNU/Hurd для использования с gccgo.

Windows

Новая платформа windows/arm Go позволяет запускать Go на Windows 10 IoT Core на 32-битных ARM-чипах, таких как Raspberry Pi 3.

AIX

Go теперь поддерживает AIX 7.2 и выше на архитектурах POWER8 (aix/ppc64). Внешняя компоновка, cgo, pprof и детектор гонок пока не поддерживаются.

Darwin

Go 1.12 — последний выпуск, который будет работать на macOS 10.10 Yosemite. Go 1.13 будет требовать macOS 10.11 El Capitan или более позднюю версию.

Теперь используется libSystem при выполнении системных вызовов на Darwin, обеспечивая совместимость с будущими версиями macOS и iOS. Переход на libSystem вызвал дополнительные проверки в App Store на использование частных API. Поскольку это считается частным, syscall.Getdirentries теперь всегда завершается с ошибкой ENOSYS на iOS. Кроме того, syscall.Setrlimit сообщает об invalid argument в местах, где ранее успешно работало. Эти последствия не специфичны для Go, и пользователи должны ожидать соответствующего поведения с реализацией libSystem в будущем.

Инструменты

go tool vet больше не поддерживается

Команда go vet была переписана для использования в качестве основы для набора различных инструментов анализа исходного кода. Подробности см. в пакете golang.org/x/tools/go/analysis. Одним из побочных эффектов является то, что go tool vet больше не поддерживается. Внешние инструменты, использующие go tool vet, должны быть изменены для использования go vet. Использование go vet вместо go tool vet должно работать со всеми поддерживаемыми версиями Go.

В рамках данного изменения экспериментальная опция -shadow больше не доступна с помощью go vet. Проверка на затенение переменных теперь может быть выполнена с помощью

<code>go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)
</code>

Тур

Тур по Go больше не включается в основную бинарную сборку. Чтобы запустить тур локально, вместо выполнения команды go tool tour, установите его вручную:

<code>go get -u golang.org/x/tour
tour
</code>

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

Кэш сборки теперь требуется как шаг на пути к устранению $GOPATH/pkg. Установка переменной окружения GOCACHE=off приведёт к сбою команд go, которые записывают данные в кэш.

Пакеты только с бинарным кодом

Go 1.12 — последний релиз, который будет поддерживать пакеты только с бинарным кодом.

Cgo

В Go 1.12 тип C EGLDisplay будет преобразован в тип Go uintptr. Это изменение аналогично тому, как Go 1.10 и более поздние версии обрабатывают типы CoreFoundation в Darwin и JNI в Java. Подробнее см. в документации по cgo.

Искажённые имена C больше не принимаются в пакетах, использующих Cgo. Вместо этого следует использовать имена, указанные в cgo. Например, используйте документированное имя cgo C.char вместо искажённого имени _Ctype_char, которое генерирует cgo.

Модули

Когда переменная GO111MODULE установлена в значение on, команда go теперь поддерживает операции с учётом модулей вне каталога модуля, при условии, что эти операции не требуют разрешения путей импорта относительно текущего каталога или явного редактирования файла go.mod. Команды, такие как go get, go list и go mod download, ведут себя так, как будто находятся в модуле с изначально пустыми требованиями. В этом режиме команда go env GOMOD сообщает о системном устройстве null (/dev/null или NUL).

Команды go, которые загружают и извлекают модули, теперь безопасны для одновременного вызова. Кэш модулей (GOPATH/pkg/mod) должен находиться в файловой системе, поддерживающей блокировку файлов.

Директива go в файле go.mod теперь указывает версию языка, используемую файлами внутри этого модуля. Если версия отсутствует, она будет установлена в текущий релиз (go 1.12). Если директива go для модуля указывает версию новее, чем используемый инструментарий, команда go попытается собрать пакеты, несмотря на это, и сообщит о несоответствии только в случае ошибки сборки.

Это изменило использование директивы go, что означает, что если вы используете Go 1.12 для сборки модуля, тем самым записывая go 1.12 в файл go.mod, вы получите ошибку при попытке собрать тот же модуль с помощью Go 1.11 через Go 1.11.3. Go 1.11.4 или более поздние версии будут работать без проблем, как и выпуски старше Go 1.11. Если вы обязаны использовать Go 1.11 через 1.11.3, можно избежать проблемы, установив версию языка равной 1.11 с помощью инструмента Go 1.12 через команду go mod edit -go=1.11.

Когда импорт не может быть разрешен с использованием активных модулей, команда go теперь будет пытаться использовать модули, упомянутые в директивах replace основного модуля, прежде чем обращаться к кэшу модулей и обычным сетевым источникам. Если соответствующая замена найдена, но директива replace не указывает версию, команда go использует псевдо-версию, производную от нулевого значения time.Time (например, v0.0.0-00010101000000-000000000000).

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

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

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

<code>// Старый код, который больше не работает корректно (он будет пропускать встроенные кадры вызовов).
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
for _, pc := range pcs[:n] {
  f := runtime.FuncForPC(pc)
  if f != nil {
    fmt.Println(f.Name())
  }
}
</code>
<code>// Новый код, который будет работать корректно.
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
for {
  frame, more := frames.Next()
  fmt.Println(frame.Function)
  if !more {
    break
  }
}
</code>

Обёртки, генерируемые компилятором для реализации выражений методов, больше не отображаются в runtime.CallersFrames и runtime.Stack. Они также не выводятся в трассировках стека при панике. Это изменение приводит инструментарий gc в соответствие с инструментарием gccgo, который уже исключал такие обёртки из трассировок стека. Клиенты этих API могут потребовать корректировки из-за отсутствующих кадров. Для кода, который должен взаимодействовать между выпусками 1.11 и 1.12, можно заменить выражение метода x.M на литерал функции func (...) { x.M(...) }.

Компилятор теперь принимает флаг -lang для установки версии языка Go, которая будет использоваться. Например, -lang=go1.8 приведет к ошибке компиляции, если программа использует псевдонимы типов, которые были добавлены в Go 1.9. Изменения языка, внесенные до Go 1.12, не применяются последовательно.

Инструментарий компилятора теперь использует разные соглашения для вызова функций Go и функций ассемблера. Это должно быть незаметно для пользователей, за исключением вызовов, которые одновременно пересекают границы Go и ассемблера и пересекают границу пакета. Если при связке возникает ошибка вроде «relocation target not defined for ABIInternal (but is defined for ABI0)», пожалуйста, обратитесь к разделу о совместимости документа по дизайну ABI.

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

Программы на Go теперь также поддерживают указатели кадров стека на linux/arm64 ради профилирующих инструментов, таких как perf. Поддержка указателей кадров стека имеет небольшую нагрузку во время выполнения, которая варьируется, но в среднем составляет около 3%. Чтобы собрать инструментарий без использования указателей кадров стека, установите GOEXPERIMENT=noframepointer при запуске make.bash.

Устаревший режим компилятора «safe» (включаемый флагом -u gcflag) был удален.

godoc и go doc

В Go 1.12 godoc больше не имеет командной строки и является только веб-сервером. Пользователи должны использовать go doc для получения справки в командной строке. Go 1.12 — последний выпуск, который будет включать веб-сервер godoc; в Go 1.13 он будет доступен через go get.

go doc теперь поддерживает флаг -all, который заставляет его выводить все экспортируемые API и их документацию, как это делала команда godoc.

go doc также теперь включает флаг -src, который показывает исходный код цели.

Trace

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

Ассемблер

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

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

Go 1.12 значительно улучшает производительность процесса очистки (sweeping), когда большая часть кучи остается активной. Это снижает задержку при выделении памяти сразу после сборки мусора.

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

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

В Linux среда выполнения теперь использует MADV_FREE для освобождения неиспользуемой памяти. Это более эффективно, но может привести к увеличению отчетного значения RSS. Ядро операционной системы будет восстанавливать неиспользуемые данные при необходимости. Чтобы вернуться к поведению Go 1.11 (MADV_DONTNEED), установите переменную окружения GODEBUG=madvdontneed=1.

Добавление cpu.extension=off в переменную окружения GODEBUG теперь отключает использование необязательных расширений набора инструкций CPU в стандартной библиотеке и среде выполнения. Это пока не поддерживается в Windows.

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

Трассировки, runtime.Caller и runtime.Callers больше не включают функции инициализации, сгенерированные компилятором. При выполнении трассировки во время инициализации глобальной переменной теперь будет отображаться функция с именем PKG.init.ializers.

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

TLS 1.3

Go 1.12 добавляет опциональную поддержку TLS 1.3 в пакете crypto/tls согласно спецификации RFC 8446. Включить её можно, добавив значение tls13=1 в переменную окружения GODEBUG. По умолчанию она будет включена в Go 1.13.

Чтобы согласовать использование TLS 1.3, убедитесь, что вы не устанавливаете явное значение MaxVersion в Config и запускаете программу с установленной переменной окружения GODEBUG=tls13=1.

Все функции TLS 1.2, кроме TLSUnique в ConnectionState и повторного согласования (renegotiation), доступны в TLS 1.3 и обеспечивают эквивалентную или лучшую безопасность и производительность. Обратите внимание, что, несмотря на обратную совместимость TLS 1.3 с предыдущими версиями, некоторые устаревшие системы могут некорректно работать при попытке согласовать этот протокол. Сертификаты с ключами RSA, слишком маленькими для обеспечения безопасности (включая 512-битные ключи), не будут работать с TLS 1.3.

Наборы шифров TLS 1.3 не настраиваемы. Все поддерживаемые наборы шифров безопасны, и если в Config установлен флаг PreferServerCipherSuites, порядок предпочтений будет основан на доступном аппаратном обеспечении.

Ранние данные (также называемые «0-RTT режимом») в настоящее время не поддерживаются как клиентом, так и сервером. Кроме того, сервер Go 1.12 не поддерживает пропуск неожиданных ранних данных, если клиент отправляет их. Поскольку 0-RTT режим TLS 1.3 предполагает, что клиенты сохраняют состояние о том, какие серверы поддерживают 0-RTT, сервер Go 1.12 не может быть частью пула балансировки нагрузки, где другие серверы поддерживают 0-RTT. Если переключить домен с сервера, который поддерживал 0-RTT, на сервер на Go 1.12, то 0-RTT необходимо отключить как минимум на весь срок жизни выданных тикетов сессии перед переключением, чтобы обеспечить бесперебойную работу.

В TLS 1.3 клиент — последняя сторона, которая говорит в хендшейке, поэтому если на сервере возникает ошибка, она будет возвращена клиенту при первом вызове Read, а не через Handshake. Например, это произойдет, если сервер отклонит сертификат клиента. Аналогично, билеты сессий теперь являются сообщениями после хендшейка, поэтому они будут получены клиентом только при его первом Read.

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

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

bufio

Методы UnreadRune и UnreadByte типа Reader теперь возвращают ошибку, если они вызываются после Peek.

bytes

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

Указатель на нулевое значение Reader теперь функционально эквивалентен NewReader(nil). До Go 1.12 первый не мог использоваться как замена второго во всех случаях.

crypto/rand

Предупреждение теперь будет выводиться в стандартный поток ошибок при первом блокировании Reader.Read на более чем 60 секунд при ожидании энтропии от ядра.

В FreeBSD Reader теперь использует системный вызов getrandom, если он доступен, иначе — /dev/urandom.

crypto/rc4

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

crypto/tls

Если клиент отправляет начальное сообщение, которое не выглядит как TLS, сервер больше не будет отвечать предупреждением, и он предоставит доступ к базовому net.Conn через новое поле Conn в RecordHeaderError.

database/sql

Теперь курсор запроса может быть получен путем передачи значения *Rows в метод Row.Scan.

expvar

Новый метод Delete позволяет удалять пары ключ/значение из Map.

fmt

Карты теперь выводятся в отсортированном по ключам порядке для облегчения тестирования. Правила сортировки следующие:

При выводе карт, неключевые значения, такие как NaN, ранее отображались как <nil>. Начиная с этого релиза, корректные значения выводятся.

go/doc

Для решения некоторых открытых проблем в cmd/doc, этот пакет получил новый бит Mode, PreserveAST, который управляет тем, очищается ли данные AST.

go/token

Тип File получил новое поле LineStart, которое возвращает позицию начала заданной строки. Это особенно полезно в программах, которые время от времени обрабатывают не-Go файлы, такие как ассемблер, но хотят использовать механизм token.Pos для идентификации позиций в файлах.

image

Функция RegisterFormat теперь безопасна для использования в параллельных горутинах.

image/png

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

io

Новый интерфейс StringWriter оборачивает функцию WriteString.

math

Функции Sin, Cos, Tan, и Sincos теперь применяют Payne-Hanek reduction для очень больших аргументов. Это обеспечивает более точные результаты, но они не будут полностью идентичны результатам предыдущих версий.

math/bits

Доступны новые операции расширенной точности Add, Sub, Mul, и Div в версиях для uint, uint32, и uint64.

net

Настройка Dialer.DualStack теперь игнорируется и является устаревшей; RFC 6555 Fast Fallback (“Happy Eyeballs”) теперь включён по умолчанию. Чтобы отключить, установите Dialer.FallbackDelay в отрицательное значение.

Аналогично, TCP keep-alive теперь включён по умолчанию, если Dialer.KeepAlive равен нулю. Чтобы отключить, установите его в отрицательное значение.

В Linux теперь используется системный вызов splice при копировании из UnixConn в TCPConn.

net/http

HTTP сервер теперь отклоняет перенаправленные HTTP запросы к HTTPS серверам с ответом в виде обычного текста “400 Bad Request”.

Новый метод Client.CloseIdleConnections вызывает CloseIdleConnections у базового Transport у Client, если он существует.

Transport больше не отклоняет HTTP ответы, которые объявляют HTTP Trailers, но не используют chunked encoding. Вместо этого, объявленные trailers теперь просто игнорируются.

Transport больше не обрабатывает значения MAX_CONCURRENT_STREAMS, объявленные HTTP/2 серверами, так строго, как это было в Go 1.10 и Go 1.11. Поведение по умолчанию теперь снова соответствует тому, как было в Go 1.9: каждое подключение к серверу может иметь до MAX_CONCURRENT_STREAMS активных запросов, после чего создаются новые TCP подключения по мере необходимости. В Go 1.10 и Go 1.11 пакет http2 блокировался и ждал завершения запросов вместо того, чтобы создавать новые подключения. Чтобы вернуть более строгое поведение, импортируйте пакет golang.org/x/net/http2 напрямую и установите Transport.StrictMaxConcurrentStreams в true.

net/url

Parse, ParseRequestURI, и URL.Parse теперь возвращают ошибку для URL-адресов, содержащих управляющие символы ASCII, включая NULL, табуляцию и символы новой строки.

net/http/httputil

ReverseProxy теперь автоматически проксирует WebSocket-запросы.

os

Новый метод ProcessState.ExitCode возвращает код завершения процесса.

ModeCharDevice был добавлен в битовую маску ModeType, что позволяет восстановить ModeDevice | ModeCharDevice при применении маски FileMode с ModeType.

Новая функция UserHomeDir возвращает домашний каталог текущего пользователя.

RemoveAll теперь поддерживает пути длиннее 4096 символов на большинстве Unix-систем.

File.Sync теперь использует F_FULLFSYNC на macOS для корректной очистки содержимого файла в постоянное хранилище. Это может привести к более медленному выполнению метода по сравнению с предыдущими версиями.

File теперь поддерживает метод SyscallConn, возвращающий значение интерфейса syscall.RawConn. Это может использоваться для вызова системно-специфичных операций над базовым дескриптором файла.

path/filepath

Функция IsAbs теперь возвращает true, если ей передано зарезервированное имя файла в Windows, например NUL. Список зарезервированных имён.

reflect

Новый тип MapIter — это итератор для перебора карты. Этот тип доступен через новый метод Value под названием MapRange. Семантика итерации соответствует семантике инструкции range, где Next используется для продвижения итератора, а Key/Value — для доступа к каждой записи.

regexp

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

runtime/debug

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

strings

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

Указатель на нулевое значение Reader теперь функционально эквивалентен вызову NewReader(nil). До версии Go 1.12 первый вариант не мог использоваться как замена второго во всех случаях.

Новый метод Builder.Cap возвращает ёмкость базового байтового среза билдера.

Функции сопоставления символов Map, Title, ToLower, ToLowerSpecial, ToTitle, ToTitleSpecial, ToUpper и ToUpperSpecial теперь всегда гарантируют возвращение корректного UTF-8. В более ранних версиях, если входные данные были некорректными UTF-8, но замены символов не требовались, данные функции некорректно возвращали исходные некорректные UTF-8 без изменений.

syscall

Теперь поддерживаются 64-битные inodes в FreeBSD 12. Некоторые типы были соответствующим образом скорректированы.

Семейство адресов Unix сокетов (AF_UNIX) теперь поддерживается в совместимых версиях Windows.

Введена новая функция Syscall18 для Windows, позволяющая выполнять вызовы с до 18 аргументами.

syscall/js

Тип Callback и функция NewCallback были переименованы; теперь они называются Func и FuncOf соответственно. Это является breaking change, но поддержка WebAssembly всё ещё экспериментальная и не подпадает под Go 1 compatibility promise. Любой код, использующий устаревшие имена, необходимо обновить.

Если тип реализует новый Wrapper интерфейс, ValueOf будет использовать его для возврата значения JavaScript для этого типа.

Значение нулевого Value изменилось. Теперь оно представляет значение JavaScript undefined вместо числа ноль. Это является breaking change, но поддержка WebAssembly всё ещё экспериментальная и не подпадает под Go 1 compatibility promise. Любой код, который полагается на нулевое значение Value как на число ноль, необходимо обновить.

Новый метод Value.Truthy сообщает о JavaScript «истинности» данного значения.

testing

Флаг -benchtime теперь поддерживает явное задание количества итераций вместо времени, когда значение заканчивается на “x”. Например, -benchtime=100x запускает бенчмарк 100 раз.

text/template

При выполнении шаблона длинные контекстные значения больше не обрезаются в ошибках.

executing "tmpl" at <.very.deep.context.v...>: map has no entry for key "notpresent"

теперь выглядит как

executing "tmpl" at <.very.deep.context.value.notpresent>: map has no entry for key "notpresent"

Если пользовательская функция, вызванная шаблоном, вызывает панику, то паника теперь перехватывается и возвращается как ошибка методом Execute или ExecuteTemplate.

time

База данных часовых поясов в $GOROOT/lib/time/zoneinfo.zip была обновлена до версии 2018i. Следует отметить, что данный ZIP-файл используется только в том случае, если база данных часовых поясов не предоставлена операционной системой.

unsafe

Недопустимо преобразовывать нулевой unsafe.Pointer в uintptr и обратно с выполнением арифметических операций. (Это уже было недопустимо, но теперь компилятор может начать вести себя некорректно.)

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

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