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

Введение в Go 1.2

С момента выпуска Go версии 1.1 в апреле 2013 года график релизов был сокращён, чтобы сделать процесс более эффективным. Этот релиз, Go версии 1.2 или коротко Go 1.2, появился примерно через шесть месяцев после 1.1, в то время как 1.1 потребовал более года после 1.0. Благодаря более короткому временному интервалу, 1.2 представляет собой меньшее изменение по сравнению с переходом от 1.0 к 1.1, но всё же содержит некоторые значительные улучшения, включая лучший планировщик и одну новую языковую конструкцию. Конечно, Go 1.2 сохраняет обещание совместимости. Большинство программ, написанных на Go 1.1 (или 1.0), будут работать без каких-либо изменений при переходе на 1.2, хотя введение одного ограничения в узкой части языка может выявить уже некорректный код (см. обсуждение использования nil).

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

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

Использование nil

Язык теперь указывает, что, по соображениям безопасности, определённые использования nil указателей гарантированно вызывают панику среды выполнения. Например, в Go 1.0, при наличии кода вроде

<code>type T struct {
  X [1<<24]byte
  Field int32
}

func main() {
  var x *T
  ...
}
</code>

nil указатель x мог использоваться для некорректного доступа к памяти: выражение x.Field могло обращаться к памяти по адресу 1<<24. Чтобы предотвратить такое небезопасное поведение, в Go 1.2 компиляторы теперь гарантируют, что любая косвенная операция через nil указатель, как показано здесь, а также в nil указателях на массивы, nil значениях интерфейсов, nil срезы и так далее, приведёт либо к панике, либо к возврату корректного, безопасного ненулевого значения. Короче говоря, любое выражение, которое явно или неявно требует оценки nil адреса, является ошибкой. Реализация может внедрять дополнительные проверки в скомпилированную программу для обеспечения такого поведения.

Дополнительные подробности находятся в документе проектирования.

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

Трёхиндексные срезы

Go 1.2 добавляет возможность указать вместимость (capacity), а также длину (length) при использовании операции среза на существующем массиве или срезе. Операция среза создаёт новый срез, описывая непрерывный участок уже созданного массива или среза:

<code>var array [10]int
slice := array[2:4]
</code>

Вместимость среза — это максимальное количество элементов, которое может содержать срез, даже после повторного срезания; она отражает размер базового массива. В этом примере вместимость переменной slice составляет 8.

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

<code>slice = array[2:4:7]
</code>

устанавливает срезу ту же длину, что и в предыдущем примере, но теперь его вместимость составляет всего 5 элементов (7-2). Использовать это новое значение среза для доступа к последним трём элементам исходного массива будет невозможно.

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

Дополнительные подробности находятся в документе проектирования.

Обновление: Это обратно совместимое изменение, которое не влияет на существующие программы.

Изменения в реализации и инструментах

Предварительная отмена выполнения в планировщике

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

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

Ограничение на количество потоков

Go 1.2 вводит настраиваемое ограничение (по умолчанию 10 000) на общее количество потоков, которое может быть в адресном пространстве одного программного обеспечения, чтобы избежать проблем с нехваткой ресурсов в некоторых средах. Обратите внимание, что горутины мультиплексируются на потоки, поэтому это ограничение не ограничивает напрямую количество горутин, а только количество, которое может одновременно блокироваться в системном вызове. На практике это ограничение трудно достичь.

Новая функция SetMaxThreads в пакете runtime/debug управляет лимитом количества потоков.

Обновление: Мало функций будут затронуты этим лимитом, но если программа завершается из-за достижения лимита, её можно изменить, чтобы вызвать SetMaxThreads для установки более высокого значения. Ещё лучше будет рефакторинг программы, чтобы она использовала меньше потоков, тем самым уменьшив потребление ресурсов ядра.

Размер стека

В Go 1.2 минимальный размер стека при создании горутины был увеличен с 4 КБ до 8 КБ. Многие программы страдали от проблем с производительностью при использовании старого размера, который часто приводил к дорогостоящему переключению сегментов стека в критических по производительности участках кода. Новое значение было определено эмпирическим путем.

С другой стороны, новая функция SetMaxStack в пакете runtime/debug управляет максимальным размером стека одной горутины. По умолчанию это 1 ГБ на 64-битных системах и 250 МБ на 32-битных системах. До Go 1.2 было слишком легко уйти в бесконечную рекурсию, которая потребляла всю память машины.

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

Cgo и C++

Команда cgo теперь будет вызывать компилятор C++ для сборки частей связанной библиотеки, написанных на C++; документация содержит дополнительные сведения.

Godoc и vet перемещены в подрепозиторий go.tools

Оба бинарных файла по-прежнему включены в дистрибутив, но исходный код команд godoc и vet был перемещён в подрепозиторий go.tools.

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

Обновление: Поскольку godoc и vet не являются частью библиотеки, никакой клиентский Go-код не зависит от их исходного кода, и обновление не требуется.

Двоичные дистрибутивы, доступные на golang.org, включают эти бинарные файлы, поэтому пользователи этих дистрибутивов не пострадают.

При сборке из исходников, пользователи должны использовать команду “go get” для установки godoc и vet. (Бинарные файлы будут продолжать устанавливаться в обычные места, а не $GOPATH/bin.)

<code>$ go get code.google.com/p/go.tools/cmd/godoc
$ go get code.google.com/p/go.tools/cmd/vet
</code>

Состояние gccgo

Ожидается, что будущий выпуск GCC 4.9 будет включать gccgo с полной поддержкой Go 1.2. В текущем (4.8.2) выпуске GCC, gccgo реализует Go 1.1.2.

Изменения в компиляторе gc и линковщике

Go 1.2 имеет несколько семантических изменений в работе компиляторной среды gc. Большинство пользователей не пострадают от этих изменений.

Команда cgo теперь работает, когда C++ включено в библиотеку, к которой происходит линковка. См. документацию cgo для получения дополнительных сведений.

Компилятор gc отображал устаревший деталь своего происхождения, когда программа не имела инструкции package: он предполагал, что файл находится в пакете main. Прошлое было стёрто, и отсутствие инструкции package теперь является ошибкой.

В ARM-среде, инструментарий поддерживает «внешнюю линковку», что является шагом к возможности сборки общих библиотек с использованием компилятора gc и предоставления поддержки динамической линковки в средах, где это необходимо.

В среде выполнения для ARM, с 5a, раньше было возможно напрямую ссылаться на внутренние переменные среды выполнения m (машина) и g (горутина), используя R9 и R10. Теперь необходимо ссылаться на них по их правильным именам.

Также в ARM, линковщик 5l (sic) теперь определяет инструкции MOVBS и MOVHS как синонимы MOVB и MOVH, чтобы сделать более очевидным разделение между знаковыми и беззнаковыми перемещениями подслов; беззнаковые версии уже существовали с суффиксом U.

Покрытие тестами

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

Инструмент cover входит в состав go.tools подрепозитория. Он может быть установлен с помощью команды

<code>$ go get code.google.com/p/go.tools/cmd/cover
</code>

Инструмент cover выполняет две функции. Во-первых, когда «go test» получает флаг -cover, он автоматически запускается, чтобы переписать исходный код пакета и вставить инструкции инструментирования. Затем тест компилируется и запускается как обычно, и выводятся базовые статистические данные о покрытии:

<code>$ go test -cover fmt
ok      fmt 0.060s  coverage: 91.4% of statements
$
</code>

Во-вторых, для более подробных отчетов, различные флаги команды «go test» могут создавать файл профиля покрытия, который программа cover, вызванная через «go tool cover», затем может анализировать.

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

<code>$ go help testflag
$ go tool cover -help
</code>

Команда go doc удалена

Команда «go doc» удалена. Обратите внимание, что сам инструмент godoc не удаляется, только его обёртка через команду go. Всё, что она делала — это отображала документацию для пакета по пути пакета, что уже делает godoc сам по себе с большей гибкостью. Поэтому она была удалена с целью уменьшения количества инструментов документации и, в рамках реорганизации godoc, поощрения лучших вариантов в будущем.

Обновление: Для тех, кто всё ещё нуждается в точной функциональности запуска

<code>$ go doc
</code>

в каталоге, поведение будет идентичным запуску

<code>$ godoc .
</code>

Изменения в команде go

Команда go get теперь имеет флаг -t, который заставляет её скачивать зависимости тестов, запускаемых пакетом, а не только зависимости самого пакета. По умолчанию, как и раньше, зависимости тестов не скачиваются.

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

В стандартной библиотеке были реализованы значительные улучшения производительности; вот некоторые из них.

Изменения в стандартной библиотеке

Пакеты archive/tar и archive/zip

В пакетах archive/tar и archive/zip произошло изменение семантики, которое может привести к поломке существующих программ. Проблема заключается в том, что оба пакета предоставляли реализацию интерфейса os.FileInfo, не соответствующую спецификации этого интерфейса. В частности, их метод Name возвращал полный путь к записи, тогда как спецификация интерфейса требует, чтобы метод возвращал только базовое имя (последний элемент пути).

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

Новый пакет encoding

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

Новые интерфейсы называются BinaryMarshaler, BinaryUnmarshaler, TextMarshaler, и TextUnmarshaler. Подробности содержатся в документации пакета и в отдельном документе проектирования.

Пакет fmt

Форматированные функции печати пакета fmt, такие как Printf, теперь позволяют получать элементы данных для печати в произвольном порядке, используя операцию индексации в спецификациях форматирования. Где бы ни требовалось извлечь аргумент из списка аргументов для форматирования, либо как значение для форматирования, либо как целое число ширины или спецификации, новая необязательная нотация индексации [n] извлекает аргумент n вместо него. Значение n является 1-индексированным. После такой операции индексации следующий аргумент для обычной обработки будет n+1.

Например, обычный вызов Printf

<code>fmt.Sprintf("%c %c %c\n", 'a', 'b', 'c')
</code>

создаст строку "a b c", но с использованием операций индексации, как в этом примере,

<code>fmt.Sprintf("%[3]c %[1]c %c\n", 'a', 'b', 'c')
</code>

результат будет ""c a b". Индекс [3] обращается к третьему аргументу форматирования, который равен 'c', [1] обращается к первому, 'a', а затем следующая операция извлечения обращается к аргументу, следующему за ним, 'b'.

Мотивацией для этой функции является возможность программно формировать инструкции форматирования для доступа к аргументам в разном порядке, что полезно для локализации, но у нее есть и другие применения:

Here's a summary of the key changes introduced in **Go 1.2**, focusing on major enhancements and modifications across various standard library packages: --- ### 🔧 **Core Language & Runtime Enhancements** - **Finalizer Relaxation**: Finalizer functions can now accept arguments of any type assignable to the formal parameter, aligning with normal function call semantics. - **Stable Sorting**: Added `sort.Stable()` function for stable sorting (less efficient than regular sort). - **Swap Functions in `sync/atomic`**: New atomic swap functions (`SwapInt32`, `SwapInt64`, etc.) allow atomic exchange of values. --- ### 📦 **Standard Library Improvements** #### `bytes` and `strings` - Added `IndexByte` in `strings` package for consistency with `bytes`. #### `crypto/tls` - Support for TLS 1.1 and 1.2 added. #### `encoding/json` - JSON unmarshaling now supports `time.Time` values. #### `fmt` - Improved handling of `time.Time` in `fmt.Printf`. #### `image` - **New `image/color/palette` package** introduced. - GIF encoding now supports custom quantizers and drawers via `Encode` and `EncodeAll`. - Added support for paletted images and error diffusion in GIF encoding. #### `io` - `Copy` prioritizes `WriterTo` over `ReaderFrom` for better performance by reducing buffering. #### `net` - **Build Tag `netgo`**: Allows building `net` package in pure Go (useful for avoiding dynamic linking). - Added `DualStack` field to `Dialer` struct to support RFC 6555 dual-stack connections. - `net` now requires cgo by default due to OS-level network setup requirements. #### `net/http` - Cookies are no longer transmitted if they violate RFC 6265; instead, an error is logged. - `ReadResponse` now accepts a `nil` request and assumes a GET request. - HTTP servers transparently handle HEAD requests by discarding response body writes. #### `os/exec` - `StdinPipe()` now returns a safe `io.WriteCloser` that can be closed without race conditions. - Previously, closing could cause a race condition. #### `runtime` - Finalizer constraints relaxed to allow more flexible argument types. #### `sync/atomic` - Added new atomic swap functions for integers, unsigned integers, and pointers. #### `syscall` - Implemented `Sendfile` for Darwin (macOS). #### `testing` - Exported `TB` interface for sharing test/benchmark code. - `AllocsPerRun` now rounds its return value to an integer for better repeatability. #### `time` - `Parse` and `Format` now support time zone offsets with seconds (e.g., `+00:34:08`). - Pattern matching in format strings is stricter (non-lowercase letters must follow standard words like “Jan” or “Mon”). #### `unicode` - Introduced `In()` function as a cleaner alternative to `IsOneOf()` for checking Unicode categories. #### `text/template` - Pointer values are automatically dereferenced when evaluating escape functions like `html`. --- ### 🧠 Additional Notes - The introduction of `netgo` build tag enables pure Go builds on systems where cgo isn't required. - Several packages have improved compatibility with international standards and RFCs. - Performance optimizations in `io.Copy`, `net`, and `sync/atomic` provide tangible benefits for concurrent and I/O-heavy applications. --- ### ✅ Summary Go 1.2 brought significant improvements to **networking**, **I/O**, **concurrency**, and **standard library usability**, along with enhanced support for **internationalization**, **security**, and **performance tuning**. It also refined the language's behavior around finalizers, sorting, and type handling, making Go even more robust and developer-friendly. Let me know if you'd like a focused breakdown of specific packages or features!
GoRu.dev Golang на русском

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