В Go 1.26 самоссылающееся ограничение дженериков вида
[T Constraint[T]] заработало не только для функций, но и для объявлений обобщённых типов. Один из приёмов, которые это открывает, это клонирование с сохранением конкретного типа.Что это решает
Представьте пайплайн, стадии которого форкаются под A/B эксперименты, и каждому форку нужно своё независимое состояние. Стадии имеют разные конкретные типы.
Если написать обобщённое копирование, которое возвращает интерфейс
Stage, вызывающий код получит абстракцию и не сможет использовать результат как *TransformStage без приведения типа. Приведение прячется где-то в глубине кода, компилятор перестаёт вам помогать, а в рантайме появляется место для паники.До 1.26 выразить «операция над
T возвращает T» на уровне объявления обобщённого типа было нельзя. Компилятор ругался на рекурсивный тип.Как это работает
Идея в том, что параметр типа
T появляется в ограничении на сам T. Тип обязан уметь клонировать именно себя:type Cloneable[T any] interface {
Clone() T
}
// DeepCopy возвращает T, а не Cloneable[T].
func DeepCopy[T Cloneable[T]](v T) T {
return v.Clone()
}Тот же приём на реальном пайплайне выглядит так:
type Stage[T any] interface {
Clone() T
Execute(ctx context.Context, event Event) (Event, error)
Name() string
}
// ForkStage возвращает T, а не Stage[T].
// Вызывающий получает *TransformStage, без приведения.
func ForkStage[T Stage[T]](s T) T {
return s.Clone()
}На вызове конкретный тип остаётся живым:
original := &TransformStage{ /* ... */ }
fork := ForkStage(original) // fork имеет тип *TransformStage
fork.SomeSpecificMethod() // доступно без приведенияТип пронесён через операцию целиком. Ни одного скрытого
.(TransformStage) в коде.Паттерн решает не переиспользование алгоритма, а сохранение идентичности типа. Когда значение порождает копию себя, вы хотите получить обратно тот же конкретный тип, а не супертип, про который компилятор молча забывает. Для форков состояния, снапшотов и любых самоклонирующихся структур это убирает целый класс приведений и связанных с ними рантайм-багов.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction