TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7364 3.13K
📎 Клонирование, которое возвращает тот же тип

В 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
  • ❤ 4
More from @goproglib
  1. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
  2. Sep 25, 2026💡 Код работает. А data race уже есть В Go можно записать значение в одной горутине, прочи…
  3. Sep 23, 2026💥 TCP/IP: что происходит с данными в сети Когда Go-приложение отправляет данные по сети,…
  4. Sep 22, 2026🔴 Встроенные функции len, make, panic — встроенные функции Go, которые можно использовать…
  5. Sep 21, 2026🤩 Go с нуля: серия базовых шпаргалок Собрали путь от Hello, World! до goroutines, channel…
  6. Sep 20, 2026🤔 Вопрос с собеседования по Go Что выведет программа? ❤️ — [1 2 3 4 5] / [1 2 10] 🔥 — [1…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →