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