Что происходит при встраивании двух интерфейсов, объявляющих один и тот же метод с одинаковой сигнатурой?
Такое встраивание корректно: одинаковое требование к методу учитывается как одно. Получившийся интерфейс требует реализацию этого метода, а тип, реализующий его один раз, удовлетворяет объединённому интерфейсу.
Встраивание интерфейсов появилось как механизм композиции небольших контрактов. Вместо дублирования длинного списка методов можно объединять специализированные интерфейсы в более общий.
Такой подход поддерживает структурную типизацию Go: новый интерфейс описывает требования к методам, а не наследование от конкретного базового типа.
При объединении интерфейсов важно отличать совпадающие требования от конфликтующих. Если два встроенных интерфейса объявляют метод с полностью одинаковым именем и сигнатурой, конфликт отсутствует.
Ошибка возникает, если методы имеют одинаковое имя, но различаются параметрами или возвращаемыми значениями. Один тип не может одновременно реализовать два метода с одинаковым именем и разными сигнатурами.
Интерфейс после встраивания рассматривается как набор требований, полученный из всех встроенных интерфейсов. Совпадающие методы с одинаковыми именем, параметрами и результатами не создают дубликат: логически это одно требование.
Тип user реализует Named, потому что его единственный метод Name удовлетворяет одинаковому требованию из обоих встроенных интерфейсов. Отдельно реализовывать метод для каждого встроенного интерфейса нельзя и не требуется.
Сигнатура должна совпадать полностью: имя метода, типы параметров, количество результатов и их типы. Совпадение только имени недостаточно. Методы с разными наборами параметров или результатов не перегружаются, поскольку Go не поддерживает перегрузку методов.
Встраивание интерфейсов не добавляет реализацию методов в конкретный тип. Оно только формирует новый контракт. Если встроенный интерфейс содержит методы, которых нет у типа, присваивание этого типа объединённому интерфейсу завершится ошибкой компиляции.
Команда объединяет интерфейсы из двух пакетов: один описывает именуемый объект, другой — объект с тем же методом Name для логирования. После встраивания разработчик опасается, что потребуется адаптер из-за дублирования метода.
Вариант с сохранением обоих встроенных интерфейсов предпочтителен: одинаковое требование объединяется автоматически, структура контракта остаётся явной, а существующие типы не меняются. Минус — изменение сигнатуры Name в одном из исходных интерфейсов может превратить совпадение в конфликт.
Можно заменить встраивание явным объявлением Name в новом интерфейсе. Это делает итоговый контракт короче, но скрывает, откуда он получен, и повышает риск рассинхронизации при изменении исходных интерфейсов. Адаптер нужен только при несовместимых методах; для полностью одинаковых методов он избыточен.
Да. Имена параметров не входят в сигнатуру метода интерфейса, поэтому методы с одинаковыми типами параметров и результатов считаются совместимыми независимо от названий параметров.
Нет. Интерфейсы не содержат реализацию и не создают поле для делегирования. Встраивание только включает методы встроенного интерфейса в набор требований нового интерфейса.
Name() string, а другой — Name() any?Объединённый интерфейс будет некорректен из-за несовместимых методов с одним именем. Метод с результатом string не считается реализацией метода с результатом any; типы результатов должны совпадать точно, несмотря на существование присваиваемости между ними.