Что происходит при именованном встраивании структур и как обращаться к полям и методам при конфликте имен в Go
Что проверяют
Различаете ли вы встраивание и обычное именованное поле и понимаете ли, что продвижение полей это правило разрешения имён, а не наследование. Вопрос любят задавать сразу после первого кода со встроенным sync.Mutex.
Как отвечать
Встраивание это поле, записанное одним типом без имени. Имя у такого поля всё равно есть, оно совпадает с именем типа без пакета, поэтому обратиться можно и коротко, и полным путём:
type Address struct{ City string }
type Person struct {
Address // встроено, поле зовётся Address
Home Address // обычное поле, продвижения нет
City string
}
p.City // поле Person, глубина 0
p.Address.City // поле встроенной структуры
p.Home.City // только полным путёмПоля и методы встроенного типа продвигаются наружу, и внешний тип за счёт этого удовлетворяет интерфейсам. Конфликт имён разрешается по глубине: побеждает самый неглубокий кандидат, поэтому собственное поле City перекрывает встроенное. Если на одной глубине оказались два одинаковых имени (например, встроены две структуры с полем City), короткое обращение становится неоднозначным.
Стоит добавить про приёмники: встраивание по значению продвигает только методы со значением-приёмником, для методов с указателем нужен встроенный *Address либо адресуемая переменная.
Где спотыкаются
Называют это наследованием и ждут переопределения. Метод внешнего типа с тем же именем закрывает вызов снаружи, но внутренние вызовы встроенного типа продолжают идти в его собственный метод: виртуальной диспетчеризации в Go нет.
Второе: думают, что одинаковые имена на одной глубине это ошибка уже при объявлении типа. Объявление проходит, компиляция падает только на использовании короткого селектора, и лечится это явным путём через имя встроенного типа.
Третье: меняют встраивание на именованное поле, считая разницу косметической. Вместе с продвижением пропадает удовлетворение интерфейсов, а encoding/json встроенную структуру разворачивает в тот же объект, именованное же поле кладёт вложенным: формат ответа тихо меняется.