Представьте, что тип переименовали через псевдоним, а затем создали новый именованный тип на его основе. Как это повлияет на сохранение реализации интерфейса?
Псевдоним сохраняет идентичность исходного типа и его методный набор, поэтому реализация интерфейса сохраняется. Новый именованный тип является отдельным типом: он не наследует методы исходного типа и должен объявить необходимые методы заново.
Псевдонимы типов нужны главным образом для совместимости и постепенной реорганизации API: другое имя указывает на тот же самый тип. Это позволяет менять структуру пакетов или имена типов без создания нового типа с отдельной типовой идентичностью.
Объявление нового именованного типа решает другую задачу — вводит типобезопасное доменное значение. Например, идентификатор пользователя и обычное число могут иметь одинаковое представление, но быть разными типами и иметь разные методы.
Ошибочное использование нового именованного типа может привести к ошибке компиляции там, где ожидалась реализация интерфейса. Особенно часто это проявляется после замены псевдонима на объявление нового типа: внешне записи похожи, но правила идентичности и набор методов различаются.
Нельзя рассуждать только по базовому типу. Для реализации интерфейса важен методный набор именно рассматриваемого типа, а не наличие у него того же представления, что у исходного типа.
Объявление вида type Alias = Original создаёт псевдоним. Alias и Original — одно и то же типовое значение с точки зрения компилятора; у них одинаковые методы, идентичность и совместимость с интерфейсами.
Объявление вида type New Original создаёт новый определённый тип. Его базовое представление связано с Original, но методы исходного типа в его методный набор не входят. Поэтому New не удовлетворяет интерфейсу только потому, что Original ему удовлетворяет.
Минимальный пример:
Псевдоним удобен для совместимости, но не создаёт отдельного барьера типов. Новый именованный тип, наоборот, защищает от случайного смешивания значений, однако требует явно воспроизвести нужные методы и выполнять явные преобразования к совместимому типу.
Если исходный тип позже получает новый метод, псевдоним автоматически видит этот метод. Новый тип сам по себе его не получает; метод нужно объявить отдельно.
В библиотеке был тип UserID, первоначально объявленный как псевдоним целого числа. Его передавали в код, ожидающий интерфейс с методом форматирования. При переходе к отдельному типу UserID старый методный набор исчез, и сборка зависимых пакетов перестала проходить.
Можно было оставить псевдоним. Это сохранило бы совместимость и не потребовало изменений, но не дало бы защиты от передачи обычного числа вместо идентификатора.
Второй вариант — создать новый именованный тип и заново объявить на нём методы. Он потребовал обновить места преобразований и тесты, зато обеспечил отдельную типовую семантику. Для публичного доменного идентификатора был выбран именно этот вариант: дополнительные изменения окупились предотвращением случайного смешивания разных идентификаторов.
Да. Псевдоним не создаёт новый тип, поэтому его методный набор полностью совпадает с методным набором исходного типа. Ограничения на доступ к неэкспортируемым методам при этом не исчезают: псевдоним не превращает закрытые методы в публичные.
Нет. Одинаковое базовое представление не делает типы идентичными и не переносит методы. Между ними обычно требуется явное преобразование, а реализацию интерфейса нужно проверять для каждого типа отдельно.
После явного преобразования значение получает статический тип исходного типа. Если исходный тип реализует интерфейс, преобразованное значение можно передать этому интерфейсу; при этом методы нового типа больше не участвуют. Такое преобразование допустимо, когда типы имеют совместимые базовые представления, но оно намеренно отбрасывает отдельную типовую идентичность нового типа.