MidТеория3 min

Что нового в Go (Golang) 1.26

Практический разбор Go 1.26: new(expr), самоссылающиеся generics, Green Tea GC по умолчанию, ускорение cgo на 30%, рандомизация heap, новые пакеты crypto/hpke, simd/archsimd, runtime/secret и обновлённый go fix

Go 1.26 вышел в феврале 2026 года, спустя полгода после Go 1.25. Это крупный релиз: он меняет правила игры в runtime (рантайме -- среде исполнения), добавляет давно ожидаемый синтаксический сахар в язык и приносит сразу несколько новых пакетов стандартной библиотеки, в том числе экспериментальных. Ниже -- разбор изменений с практическими примерами. Минимальная версия для сборки компилятора (bootstrap -- начальная загрузка) поднялась до Go 1.24.6.

Эта статья дополняет общий обзор релиза в файле 6.go126.md: здесь акцент на практике -- что именно поменялось в коде, который вы пишете каждый день.

Языковые изменения

new() теперь принимает выражение

Раньше встроенная функция new (new -- «создать новый») принимала только тип и возвращала указатель на его нулевое значение (zero value -- значение по умолчанию). Чтобы получить указатель на конкретное значение, приходилось заводить вспомогательную переменную или дженерик-хелпер.

// Go 1.25 и раньше: указатель на значение через временную переменную
age := 42
p := &age // *int, указывающий на 42

// Либо через дженерик-хелпер, который многие копировали из проекта в проект
func ptr[T any](v T) *T { return &v }
p2 := ptr(42)

В Go 1.26 new принимает произвольное выражение и сразу возвращает указатель на его значение:

// Go 1.26: указатель на значение одним вызовом
p := new(42)          // *int, указывающий на 42
s := new("hello")     // *string
t := new(time.Now())  // *time.Time

Это особенно удобно в структурах с опциональными (необязательными) полями-указателями, например при сериализации в JSON:

type User struct {
    Name string
    Age  *int // указатель отличает "0 лет" от "поле не задано"
}

func makeUser(name string, born time.Time) User {
    return User{
        Name: name,
        Age:  new(yearsSince(born)), // никаких временных переменных
    }
}

Важная деталь: выражение вычисляется один раз, и Go копирует результат в свежую область памяти (allocation -- выделение памяти). Это полноценная замена сотням мелких хелперов ptr[T], которые жили в каждом втором проекте.

Самоссылающиеся generics (дженерики)

Параметр типа (type parameter -- параметр-тип) теперь может ссылаться сам на себя в своём же списке ограничений (constraints -- ограничения). Это снимает старое ограничение компилятора и открывает чистый способ описывать рекурсивные API.

// Ограничение, ссылающееся на собственный параметр типа
type Adder[A Adder[A]] interface {
    Add(A) A
}

// Теперь можно писать обобщённые алгоритмы над "самозамкнутыми" типами
func Sum[A Adder[A]](items []A) A {
    var acc A
    for _, x := range items {
        acc = acc.Add(x)
    }
    return acc
}

Главная практическая польза -- типобезопасные fluent-builder'ы (текучие построители) и рекурсивные структуры данных, где метод должен возвращать именно конкретный тип наследника, а не абстрактный интерфейс:

// Builder (построитель), который возвращает свой же конкретный тип
type Builder[B Builder[B]] interface {
    With(key, value string) B
}

Раньше такие конструкции либо не компилировались, либо требовали обходных хитростей с пустыми интерфейсами и приведением типов (type assertion -- утверждение о типе).

Runtime (рантайм) и производительность

Green Tea GC включён по умолчанию

Сборщик мусора (garbage collector -- сборщик мусора) под кодовым именем Green Tea («зелёный чай»), который в Go 1.25 был экспериментальным, в Go 1.26 стал работать по умолчанию. По официальным данным он снижает накладные расходы GC на 10--40%, а на новых процессорах amd64 (Intel Ice Lake, AMD Zen 4 и новее) даёт дополнительно около 10%.

Ничего менять в коде не нужно -- ускорение приходит само после обновления. Если новый GC по каким-то причинам мешает (например, нашли регрессию), его можно временно отключить:

# Вернуться к старому сборщику мусора
GOEXPERIMENT=nogreenteagc go build ./...

Подробный разбор внутреннего устройства Green Tea GC (регионы, generational hint -- поколенческая подсказка) есть в файле 6.go126.md. Здесь важно запомнить главное: это поведение по умолчанию, и оно бесплатно для разработчика.

Рандомизация базового адреса heap (кучи)

На 64-битных платформах рантайм теперь рандомизирует (случайно сдвигает) базовый адрес heap (кучи -- области динамической памяти) при старте программы. Это мера безопасности, аналог ASLR (Address Space Layout Randomization -- рандомизация размещения адресного пространства): атакующему сложнее предсказать, где в памяти лежат объекты, и эксплуатировать уязвимости с прямой работой с адресами.

# Отключить рандомизацию (например, для воспроизводимых дампов памяти при отладке)
GOEXPERIMENT=norandomizedheapbase64 go run ./...

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

Ускорение вызовов cgo на ~30%

cgo (мост между Go и C-кодом) исторически был «дорогим»: каждый переход из Go в C и обратно требовал переключения стека и синхронизации с планировщиком (scheduler -- планировщик горутин). В Go 1.26 базовые накладные расходы на вызов cgo снижены примерно на 30%.

Это особенно заметно в коде, который часто дёргает C-библиотеки в горячем цикле (hot loop -- горячий цикл):

/*
#include <math.h>
*/
import "C"

// Такой цикл с частыми вызовами C-функций в Go 1.26 заметно быстрее
func sumSqrt(values []float64) float64 {
    var total float64
    for _, v := range values {
        total += float64(C.sqrt(C.double(v)))
    }
    return total
}

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

Выделение слайсов на стеке в большем числе случаев

Компилятор стал умнее в escape-анализе (escape analysis -- анализ убегания значений из стека в кучу). Теперь backing array (подложку -- внутренний массив) слайса в большем числе ситуаций удаётся разместить на стеке (stack -- стек вызовов), а не в куче. Стековые выделения не нагружают GC и освобождаются автоматически при выходе из функции.

// Если слайс не "убегает" за пределы функции,
// его внутренний массив теперь чаще живёт на стеке -- 0 нагрузки на GC
func process(n int) int {
    buf := make([]int, n) // в подходящих условиях -- стек, а не куча
    for i := range buf {
        buf[i] = i * i
    }
    return buf[n-1]
}

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

go build -gcflags=all=-d=variablemakehash=n ./...

Инструменты

Обновлённый go fix -- дом «модернизаторов»

Команда go fix («исправить») полностью переработана. Раньше она занималась в основном миграцией старого кода времён Go 1.0. Теперь это центральное место для модернизаторов (modernizers -- инструменты обновления кода до современных идиом): десятки автоматических правок, приводящих код к актуальному стилю и новым API стандартной библиотеки.

# Прогнать модернизаторы по всему проекту
go fix ./...

Например, go fix может заменить устаревшие конструкции на современные эквиваленты (циклы по индексу -- на range по целому числу из Go 1.22, ручные проверки -- на хелперы из slices/maps и т.д.). Под капотом используется тот же фреймворк анализа, что и у go vet (vet -- «проверять»).

Дополнительно появился source-level inliner (встраивание на уровне исходного кода) через директиву //go:fix inline: автор библиотеки может пометить функцию как «встраиваемую», и go fix развернёт её вызовы в местах использования.

//go:fix inline
func Add(a, b int) int { return a + b } // go fix может заменить вызовы Add(x, y) на (x + y)

Новые пакеты стандартной библиотеки

crypto/hpke -- гибридное шифрование

Новый пакет crypto/hpke реализует HPKE (Hybrid Public Key Encryption -- гибридное шифрование с открытым ключом) по стандарту RFC 9180. HPKE объединяет три примитива в едином API: KEM (Key Encapsulation Mechanism -- механизм инкапсуляции ключа), KDF (Key Derivation Function -- функция выведения ключа) и AEAD (Authenticated Encryption with Associated Data -- аутентифицированное шифрование). На практике это сводит end-to-end (сквозное) шифрование к паре операций: запечатать (seal) и распечатать (open).

// Концептуально: отправитель запечатывает сообщение публичным ключом получателя,
// получатель распечатывает своим приватным ключом
ciphertext, enc, err := sender.Seal(recipientPublicKey, plaintext, aad)
plaintext, err := recipient.Open(enc, ciphertext, aad)

Пакет включает поддержку post-quantum (постквантовых) гибридных KEM, что важно для защиты от будущих квантовых атак.

simd/archsimd (экспериментальный) -- SIMD-операции

Экспериментальный пакет simd/archsimd даёт доступ к SIMD-инструкциям (Single Instruction, Multiple Data -- одна инструкция над многими данными) конкретной архитектуры процессора. На момент релиза поддерживается только amd64 с векторными типами на 128, 256 и 512 бит. SIMD позволяет обрабатывать сразу несколько чисел одной машинной инструкцией -- это ускоряет числодробилки: обработку изображений, аудио, матричные вычисления.

# Пакет за экспериментальным флагом
GOEXPERIMENT=simd go build ./...

Поскольку пакет экспериментальный, его API может измениться в следующих релизах -- использовать в продакшене пока рано.

runtime/secret (экспериментальный) -- безопасное стирание секретов

Экспериментальный пакет runtime/secret («секрет») решает тонкую проблему криптографии: после работы с секретными данными (ключами, паролями) их копии могут оставаться в регистрах процессора, на стеке и в куче. Стандартное обнуление переменной компилятор иногда выкидывает как «бесполезное». Этот пакет гарантирует безопасное стирание временных копий секрета, поддерживая forward secrecy (прямую секретность -- свойство, при котором утечка ключа сейчас не раскрывает прошлый трафик).

# Поддержка amd64 и arm64 на Linux, за экспериментальным флагом
GOEXPERIMENT=runtimesecret go build ./...

Краткая сводка

Изменение Где Суть
new(expr) язык указатель на значение одним вызовом
самоссылающиеся generics язык рекурсивные типобезопасные API
Green Tea GC runtime по умолчанию, GC быстрее на 10--40%
рандомизация heap runtime защита по типу ASLR
cgo −30% runtime дешевле переходы Go↔C
слайсы на стеке компилятор меньше нагрузка на GC
обновлённый go fix инструменты автомодернизация кода
crypto/hpke stdlib гибридное шифрование RFC 9180
simd/archsimd stdlib (эксп.) SIMD-векторизация на amd64
runtime/secret stdlib (эксп.) безопасное стирание секретов

Большинство улучшений производительности (Green Tea GC, cgo, стековые слайсы) приходят бесплатно -- достаточно пересобрать проект новым компилятором. Языковые новинки (new(expr), самоссылающиеся generics) и go fix стоит освоить сразу: они напрямую упрощают повседневный код.

Проверь себя

Что делает new(42) в Go 1.26?

Что произошло с Green Tea GC в Go 1.26?

На сколько примерно снизились базовые накладные расходы вызова cgo в Go 1.26?

Чем стала команда go fix в Go 1.26?