🦄 Go 1.27: дженерик-методы, json/v2 в проде и профиль утёкших горутин🟠
Draft release notes — релиз ожидается уже в августеГлавное — дженерик-методыЯ
писал об этом ещё на этапе пропозала, поэтому подробно описывать тут не буду.
Вкратце: метод теперь может объявлять собственные типовые параметры. Долгое время такое приходилось писать в виде обычной функции:
// Было — только обычной функцией
func MapSlice[T, U any](s Slice[T], f func(T) U) Slice[U]
// Стало — можно методом
func (s Slice[T]) Map[U any](f func(T) U) Slice[U]
То есть, мы писали
MapSlice(s, f) вместо
s.Map(f). Потому что метод так не умел. Теперь умеет.
Из ограничений: методы интерфейсов свои типовые параметры объявлять не могут, и дженерик-метод не может реализовать метод интерфейса.
Другие изменения в языке:1. Поле встроенной структуры теперь можно задать прямо в литерале:
// Было
u := User{Timestamps: Timestamps{CreatedAt: now}, Name: "Вася"}
// Стало
u := User{CreatedAt: now, Name: "Вася"}
Читать и писать в
u.CreatedAt напрямую можно было всегда, а теперь и в литерале.
Тикету одиннадцать лет 🙃
2. Компилятор наконец-то сам везде выводит тип:
func g[T any](T) {}
type S struct{ f func(int) }
// Было
s.f = g // ok
s = S{f: g} // ошибка, нужно g[int]
// Стало
s = S{f: g} // okТип поля известен, T выводится однозначно — но в литерале это почему-то не работало. Теперь работает везде: литералы структур, массивов, слайсов и мап, отправка в канал, конверсии.
Griesemer в
issue сам назвал это скорее багом, чем языковым изменением.
Доехал encoding/json/v2И самое интересное — v1 теперь под капотом работает на v2. Поведение сохранено, тексты ошибок могут отличаться. Marshal примерно как был, Unmarshal заметно быстрее.
Мигрировать не обязательно, v1 API будут поддерживать и дальше. Если что-то сломается —
GOEXPERIMENT=nojsonv2.
Goroutine leak profile доехал из экспериментального в стабильныйИскать тут:
/debug/pprof/goroutineleakРантайм ловит утёкшие горутины через GC — если горутина заблокирована на примитиве, до которого не дотянется ни одна runnable-горутина (и ни одна из тех, кого те могли бы разбудить), значит разблокировать её некому. Ловит не всё, но большой класс — да. Сделал Vlad Saioc из Uber.
Что ещё интересного:- Новый пакет uuid в стандартной библиотеке ✨
-
Response.Body при Close сам дочитывает остаток тела — чтобы соединение ушло в пул, а не закрывалось. В разумных пределах и только для HTTP/1. Наш любимый
io.Copy(io.Discard, resp.Body) можно выкидывать в большинстве случаев 🔥
- Некоторые аллокации мелких объектов (<80 байт) до 30% быстрее. В реальных allocation-heavy программах ~1%, бинарь +60 КБ
-
strings.CutLast и
bytes.CutLast — режут по последнему вхождению сепаратора
- net/url: URL.Clone() и Values.Clone()
- go doc умеет
package@version и флаг -ex для примеров
- Unicode 15 → 17
- macOS 13 Ventura и новее. Как и обещали в 1.26
————
🟢 Дженерик-методы — та фича, которую ждали с самого выхода дженериков в 1.18. Как по мне, главный итог даже не «стало можно», а то, что перестанет расти пакетный неймспейс из функций, которые логически принадлежат типу.
А вот с json/v2 интересно. Тихо переключить v1 на новую реализацию — смелый ход, учитывая сколько кода в мире парсит этот пакет. Обещают такое же поведение, но так не бывает. Да и
GOEXPERIMENT=nojsonv2 в релиз-нотах как бы намекает 🌚
Вполне можно ожидать, что в первые месяцы будем читать байки про
«а у нас после апгрейда...».
uuid в стандартной библиотеке — это здорово. Сколько лет
google/uuid был де-факто стандартом — пора уже добавить в stdlib.
Релиз ещё черновой, так что что-то может доехать или отвалиться.
————
Я сейчас готовлю большой
интерактивный разбор этого релиза на своей новой платформе, которую недавно
анонсировал. Если вам что-то из текущего поста было непонятно — после прочтения разбора поймёте, там я постарался изложить всё подробно и простым языком, да ещё и с живыми примерами.
Скорее всего, опубликую уже на днях (и разбор, и первую статью из обновлённой серии про планировщик).
#go1_27 #go_official #generics #json