Границы дженериков †
На ревью Аня осадила Мишу: в коде появился дженерик, под которым под разными типами пряталось разное поведение. Она вернула PR с комментарием: «Повторяется логика, а не просто тип».
у дженериков есть границы — до Go 1.26 включительно методы не могли иметь собственные параметры типа (с Go 1.27 разрешены), производительность зависит от конкретного случая, а применять их стоит там, где повторяется логика, а не просто тип.
Чего дженерики не умеют
Методы не могли иметь собственные параметры типа до Go 1.26 включительно; с Go 1.27 это разрешено. Дженерик-функция и дженерик-тип есть всегда, а вот метод с отдельным [T] внутри обычного типа на версиях до 1.27 — нет. Если методу нужен свой тип, а код собирается старыми версиями, обходят это либо выносом логики в дженерик-функцию, либо делая сам тип дженериком. Аня показывает Мише именно такой обходной путь в его коде — он корректен для версий, на которых живёт «Полка».
Производительность — без гарантий
В Go нет классической мономорфизации C++, где каждая инстанциация — отдельный скомпилированный код. Вместо этого компилятор использует формы (GC shape stenciling) и словари для типов — деталь реализации. Из-за этого «дженерики быстрее или медленнее» зависит от конкретного случая. Мериют бенчмарком, а не рассуждением (инструмент — в).
Когда дженерики уместны
Главный ориентир — повторяется ли логика, а не просто тип. Если функция делает одно и то же для int и для string, и разница только в типе — дженерик оправдан. Если под разными типами скрывается разное поведение, дженерик лишь спрячет эту разницу за switch по типам — и тогда честнее интерфейс. Именно такой случай Аня и нашла на ревью.
Для контейнеров и мелких утилит вроде chunk, filter, contains дженерики хороши. Для доменной логики, где общность надумана, они приносят больше шума, чем пользы. Стандартная библиотека так и поступила: добавила slices, maps и cmp с дженериками, но не переписала на них всё подряд.
Вы узнаете:
- чем дженерик отличается от подхода
io.Reader - что дают пакеты
slices,maps,cmp
Проверьте себя
Метод func (b Box) Map[T any](...) компилируется?
Сортировка слайсов разных числовых типов — дженерик или интерфейс?
Что известно о производительности дженериков в Go?
правильных ответов
Границы: методы без своих типов-параметров до Go 1.26 включительно (с Go 1.27 разрешены); производительность — через бенчмарк; применять там, где общая логика, а не общий тип.
10 000 ₽ · 60 минут · онлайн