Продвижение методов
Продвижение методов (method promotion) в Go — это механизм, позволяющий вызывать методы вложенной (анонимной) структуры непосредственно через экземпляр внешней структуры. Когда мы вкладываем одну структуру в другую как анонимное поле, все методы вложенной структуры становятся доступны и для внешней структуры.
Это похоже на наследование в ООП, но в Go это реализовано
через композицию. Продвижение методов работает только для
struct и interface, а также только в том случае,
если поле является анонимным (без имени).
Синтаксис
type Inner struct {
Value int
}
func (i Inner) Get() int {
return i.Value
}
type Outer struct {
Inner // анонимное поле
}
Теперь методы Inner доступны через Outer.
Пример
Давайте создадим вложенную структуру User с методом
GetName и внешнюю структуру Admin,
которая будет иметь анонимное поле User:
package main
import "fmt"
type User struct {
Name string
}
func (u User) GetName() string {
return u.Name
}
type Admin struct {
User
Level int
}
func main() {
admin := Admin{
User: User{Name: "Alice"},
Level: 5,
}
res := admin.GetName()
fmt.Println(res)
}
Результат выполнения кода:
"Alice"
Метод GetName был продвинут из структуры User
в структуру Admin, и мы можем вызвать его напрямую
через экземпляр Admin.
Пример
Если метод вложенной структуры принимает параметры,
он также продвигается. Рассмотрим структуру Counter
с методом Add:
package main
import "fmt"
type Counter struct {
Count int
}
func (c *Counter) Add(n int) {
c.Count += n
}
func (c Counter) Get() int {
return c.Count
}
type ExtendedCounter struct {
*Counter
Name string
}
func main() {
ec := ExtendedCounter{
Counter: &Counter{Count: 10},
Name: "MyCounter",
}
ec.Add(5)
res := ec.Get()
fmt.Println(res)
}
Результат выполнения кода:
15
Методы Add и Get были продвинуты,
и мы работаем с ними как с собственными методами
структуры ExtendedCounter.
Пример
Если внешняя структура имеет метод с тем же именем, что и у вложенной, то метод внешней структуры переопределяет продвинутый метод. Проверим это на примере:
package main
import "fmt"
type Base struct {
Value string
}
func (b Base) Get() string {
return "Base: " + b.Value
}
type Wrapper struct {
Base
Value string
}
func (w Wrapper) Get() string {
return "Wrapper: " + w.Value
}
func main() {
w := Wrapper{
Base: Base{Value: "base"},
Value: "wrapper",
}
res := w.Get()
fmt.Println(res)
}
Результат выполнения кода:
"Wrapper: wrapper"
Метод Get структуры Wrapper переопределил
продвинутый метод. Чтобы вызвать метод вложенной структуры,
нужно обратиться к ней напрямую: w.Base.Get().
Смотрите также
-
статью
Методы структур,
которая описывает объявление методов для структур -
статью
Встраивание структур,
которая описывает композицию структур через анонимные поля -
статью
Анонимные поля,
которая описывает поля без имени -
статью
Продвижение полей,
которая описывает доступ к полям вложенных структур