В обобщённой функции ограничение одновременно задаёт базовый тип int и требует метод: что произойдёт с множеством допустимых типов?
Множество допустимых типов станет пересечением двух условий: тип должен иметь базовый тип int и реализовывать требуемый метод. Поэтому именованный тип на основе int подойдёт только при наличии этого метода, а сам встроенный int — нет.
До появления обобщений интерфейсы Go в основном описывали поведение через набор методов. С появлением generics интерфейсные ограничения получили дополнительную роль: они стали описывать множество допустимых типов, включая требования к базовому типу через ~.
Это позволило выразить ограничения вроде «любой именованный тип на основе int, но только если он предоставляет определённую операцию». Такой подход отделяет представление типа от требований к его поведению.
Ограничение с базовым типом само по себе не означает наличие методов. Например, тип с underlying type int может быть пользовательским именованным типом, но его методный набор определяется отдельно.
Если считать, что условие ~int автоматически включает любой тип с методами или что встроенный int может удовлетворить пользовательскому методу, обобщённая функция не скомпилируется для части ожидаемых аргументов. Это особенно важно при проектировании API: добавление метода сужает множество типов, допустимых в качестве параметра.
Интерфейсное ограничение с несколькими элементами задаёт пересечение условий. Тип обязан одновременно принадлежать множеству типов с базовым типом int и иметь метод с требуемой сигнатурой.
Минимальный пример:
Score подходит: его базовый тип — int, а метод Value присутствует. Значение типа int не подходит, поскольку у встроенного типа нет метода Value; условие ~int не добавляет методы автоматически.
Важно различать именованный тип и псевдоним. Псевдоним type Score = int не создаёт новый тип и не позволяет добавить к int методы. Кроме того, метод с указательным получателем удовлетворяет ограничению только для типа-указателя, если именно его методный набор содержит требуемый метод.
Для параметра типа это означает, что компилятор разрешает только операции, гарантированные ограничением. Если в нём указан метод Value, его можно вызывать у значения типа T, но сам факт наличия ~int не даёт произвольного доступа к методам или преобразованиям.
Основной компромисс — точность против универсальности. Более строгое ограничение предотвращает некорректные инстанцирования и позволяет безопасно использовать метод, но уменьшает число типов, пригодных для функции.
Команда проектирует функцию форматирования числовых идентификаторов. Рассматривались два варианта: принять любой тип с базовым типом int или дополнительно потребовать метод форматирования.
Первый вариант универсальнее, но форматирование пришлось бы задавать отдельно — например, через внешний callback или преобразование к строке. Второй вариант гарантирует единое поведение, но исключает обычный int и пользовательские типы без нужного метода.
Выбран второй вариант для доменных типов: идентификаторы представлены именованными типами, а метод форматирования является частью их контракта. В результате ошибочные типы отбраковываются на этапе компиляции, а функция не содержит динамических проверок; цена решения — необходимость явно реализовать метод для каждого поддерживаемого типа.
~int сам тип int?Да, множество, заданное ~int, включает int и именованные типы с базовым типом int. Однако после добавления требования метода применяется пересечение. Сам int из итогового множества исключается, если у него нет требуемого метода.
Нет. Метод должен совпадать по полной сигнатуре: имени, параметрам и результатам. Метод Value() int не удовлетворяет требованию Value() string, даже если имя одинаковое; Go не поддерживает ковариантность результатов для реализации интерфейсов.
Изменится допустимый типовой аргумент. Если метод определён только у *Score, то Score не удовлетворяет ограничению, требующему этот метод, а *Score при этом не удовлетворит ограничению ~int, поскольку его базовый тип — указательный тип, а не int. В таком дизайне требования к базовому типу и методному набору могут оказаться несовместимыми.