Хороший обзор рекомендаций в отношении структуры Go-проектов представила Кэт Зиен (Kat Zien) в своем докладе на конференции GopherCon 2018 (https://oreil.ly/0zHY4).
Если набор методов конкретного типа содержит все методы из набора методов интерфейса, то этот конкретный тип реализует интерфейс. Это означает, что этот конкретный тип может быть присвоен переменной или полю, в качестве типа которого указан данный интерфейс.
Кроме того, Go не обеспечивает динамическую диспетчеризацию конкретных типов. Методы встроенного поля не знают о том, что они являются встроенными. Если метод встроенного поля будет вызывать другой метод этого встроенного поля и вмещающая структура будет обладать методом с таким же именем, то метод встроенного поля не будет вызывать метод вмещающей структуры. Эту особенность поведения показывает следующий пример кода, который вы можете запустить в онлайн-песочнице (https://oreil.ly/yN6bV):
type Inner struct {
A int
}
func (i Inner) IntPrinter(val int) string {
return fmt.Sprintf("Inner: %d", val)
}
func (i Inner) Double() string {
return i.IntPrinter(i.A * 2)
}
type Outer struct {
Inner
S string
}
func (o Outer) IntPrinter(val int) string {
return fmt.Sprintf("Outer: %d", val)
}
func main() {
o := Outer{
Inner: Inner{
A: 10,
},
S: "Hello",
}
fmt.Println(o.Double())
}
Запустив этот код, вы получите следующий результат:
Inner: 20
Хотя встраивание одного конкретного типа в другой не позволяет вам использовать внешний тип в качестве внутреннего типа, методы встроенного поля добавляются в набор методов вмещающей структуры. Это означает, что благодаря встраиванию можно обеспечить реализацию интерфейса вмещающей структурой.