Экспериментальные функции в Go — это способ получить обратную связь от сообщества до того, как фича станет постоянной. Иногда это новые пакеты в стандартной библиотеке, иногда изменения в компиляторе или рантайме. Редко — ломающие изменения в поведении языка. Если что-то пошло не так, фичу могут доработать или вовсе забросить.
Последние примеры: в Go 1.24 появился экспериментальный testing/synctest — после отзывов API подправили и сделали общедоступным в Go 1.25. В Go 1.25 экспериментально запустили новый сборщик мусора, и он стал по умолчанию в Go 1.26. А в Go 1.21 экспериментировали с семантикой переменной цикла — ломающее изменение, но это закрыло частый баг, и в Go 1.22 поведение стало стандартом.
Жизненный цикл чаще всего такой: фича выходит как off-by-default — включаешь её через GOEXPERIMENT. Если всё хорошо, через релиз-два она становится on-by-default. Иногда дают временную возможность отключить старую версию. Например, новый GC в Go 1.26 включён по умолчанию, но старый ещё можно вернуть.
Бывает и по-другому. Новый инлайнер из Go 1.22 до сих пор off-by-default и под оценкой. Memory arenas после негативных отзывов заморозили — могут вообще удалить. А Swiss tables для map пошли сразу в продакшн, команда Go была уверена в реализации. Откатить пока можно, но не факт, что надолго.
Есть три основных состояния: off-by-default под оценкой, off-by-default заморожен, on-by-default с временным opt-out. И есть «вечные эксперименты» — они тоже управляются через GOEXPERIMENT, но никогда не станут стандартом. Например, field tracking для диагностики доступа к полям структур или static lock ranking для поиска дедлоков в рантайме. Оба висят уже десять лет.
Узнать, какие эксперименты доступны сейчас, непросто. Официальной страницы нет. Можно запустить go doc goexperiment.Flags, посмотреть src/internal/buildcfg/exp.go в исходниках и сверить с релиз-нотами и GitHub issues. По состоянию на Go 1.26, например, есть HeapMinimum512KiB (уменьшает минимальный размер кучи до 512 КБ для ограниченных сред, скорее дремлет), Arenas (на паузе), NewInliner (под оценкой с Go 1.22), JSONv2 (новый encoding/json/v2, под оценкой), RuntimeSecret (пакет для зануления памяти, только Linux amd64/arm64), GoroutineLeakProfile (профиль pprof для утечек горутин), SIMD (SIMD-операции для amd64), RuntimeFreegc (немедленное переиспользование памяти без ожидания GC), SizeSpecializedMalloc (специализированные malloc под размер класса). Включены по умолчанию и дают временный opt-out: LoopVar, Dwarf5, RandomizedHeapBase64, GreenTeaGC, RegabiWrappers, RegabiArgs.
Включаются эксперименты через переменную GOEXPERIMENT. Off-by-default — список названий строчными буквами через запятую: GOEXPERIMENT=jsonv2,goroutineleakprofile go build ./.... On-by-default отключаются префиксом no: GOEXPERIMENT=nogreenteagc go build ./.... Можно смешивать. Разные значения GOEXPERIMENT считаются разными сборками, кеш разделяется.
Для обычного разработчика, который просто пишет на Go, большинство экспериментов неактуальны. Стоит обратить внимание: GreenTeaGC — вы уже используете его в Go 1.26, если проблемы — можно отключить; Dwarf5 — тоже уже включён; JSONv2 — не переключайтесь пока, но потестируйте, чтобы быть готовым; GoroutineLeakProfile — сразу полезно, если подозреваете утечку горутин; RuntimeSecret — для криптографии и чувствительных данных; RuntimeFreegc — если ваш код сильно нагружает GC, стоит померить производительность.
Важно: экспериментальные функции не покрываются совместимостью Go. Их API, поведение и производительность могут меняться. Не стоит завязываться на них до финализации. Но если вы знаете, что эксперимент повлияет на ваш код, когда станет стандартом, — попробуйте, запустите бенчмарки и дайте фидбек. Релиз-ноты в последнее время стали лучше описывать эксперименты, так что следить за ними проще.