Go: Generics

11 вопросов

1 Что такое дженерики (generic programming) в Go?

С Go 1.18: параметризация типов и функций типами. Объявление: func F[T any](x T) T или type Box[T any] struct { V T }. Позволяет писать общий код для разных типов без interface{} и приведения типов. Компилятор генерирует специализированный код для каждого используемого типа.

Открыть отдельно →
2 Зачем нужны дженерики в Go?

Переиспользование кода для разных типов без копирования и без потери типобезопасности. Типобезопасные контейнеры (слайсы, map), общие алгоритмы (min, max, sort), уменьшение приведения типов и reflection. Интерфейсы остаются для поведения; дженерики - когда важен конкретный тип, но логика одна.

Открыть отдельно →
3 Когда использовать интерфейсы, когда дженерики?

Интерфейсы - когда важно поведение (методы), тип может быть разным в runtime. Дженерики - когда нужна одна логика для разных типов, тип известен на этапе компиляции. Пример: io.Reader - интерфейс; функция func First[T any](s []T) T - дженерик. Часто комбинируют: ограничение типа дженерика интерфейсом.

Открыть отдельно →
4 Что такое type constraints (ограничения типов)?

Ограничение задаёт, какие типы можно подставлять в параметр типа. Встроенные: any (любой), comparable (сравнимые). Интерфейс как ограничение: func F[T io.Reader](r T) - только типы с методом Read. Пакет golang.org/x/exp/constraints: Ordered, Integer и др. Синтаксис: func F[T Constraint](...) .

Открыть отдельно →
5 Что делает оператор ~ (tilde) в ограничениях?

Тильда в интерфейсе ограничений: ~T означает "любой тип с underlying type T". Например, type MyInt int удовлетворяет ~int, но не int. Используется в constraints: type Number interface { ~int | ~int64 | ~float64 } - все числовые типы с таким базовым типом.

Открыть отдельно →
6 Можно ли объявить дженерик-метод?

Метод не может иметь своих параметров типа - только тип получателя может быть параметризован. То есть func (r T) M[U any]() не допускается. Параметры типа задаются у типа: type S[T any] struct{}; func (s S[T]) M(). Для "дженерик-метода" делают функцию-обёртку с параметром типа.

Открыть отдельно →
7 Как работает type inference для дженериков?

Компилятор выводит параметры типа по аргументам вызова. slices.Clone(s) выводит тип элемента из s. Явно: F[int](42). Вывод работает по аргументам и по результатам (если нужно). Нельзя вывести - нужно указать тип явно: F[int]().

Открыть отдельно →
8 Что такое ограничение comparable?

Встроенное ограничение comparable - типы, которые можно сравнивать с == и !=. Нужно для ключей map и для обобщённых функций сравнения. Не сравнимы: слайсы, map, функции. Сравнимы: базовые типы, указатели, каналы, интерфейсы, структуры и массивы из сравниваемых полей.

Открыть отдельно →
9 Какие ограничения у дженериков в Go?

Методы не могут иметь свои параметры типа. Нет специализации (specialization). Нет ковариантности/контравариантности. Нельзя использовать type assertion к параметру типа в runtime (тип стирается). Дженерики не заменяют интерфейсы - те остаются для полиморфизма в runtime.

Открыть отдельно →
10 Какие пакеты стандартной библиотеки используют дженерики?

С Go 1.18+: slices (Sort, Clone, Contains, Equal и др.), maps (Keys, Values, Clone, Equal), sync (Pool с типом), container/list и др. получили обобщённые варианты или новые API. Пакеты slices и maps - основные примеры использования дженериков в stdlib.

Открыть отдельно →
11 Влияют ли дженерики на размер бинарника?

Да. Компилятор генерирует код для каждого набора параметров типа (monomorphization). Больше использований разных типов - больше кода. Обычно прирост небольшой; дублирование ограничено реально используемыми комбинациями. Оптимизация: избегать лишних параметров типа и не специализировать по множеству типов без нужды.

Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.