Lekcje modułu (3/5)
Kompozycja (osadzanie)
Idź nie ma dziedzictwa. Idiomatyczna odpowiedź na pytanie: ponowne użycie brzmi: skład, a w szczególności osadzanie: obejmuje jeden rodzaj wewnątrz innego, nie nadając mu nazwy pola. Dziedziny i metody typ osadzony zostaje promowany i staje się bezpośrednio dostępny, jak gdyby należeli do typu zewnętrznego.
Osadzanie struktur
type Animal struct {
Name string
}
func (a Animal) Greet() string {
return "ciao da " + a.Name
}
type Dog struct {
Animal // embedding — NO field name
Breed string
}
c := Dog{
Animal: Animal{Name: "Rex"},
Breed: "Pastore",
}
fmt.Println(c.Name) // "Rex" — promoted from Animal
fmt.Println(c.Greet()) // "ciao da Rex" — promoted method
fmt.Println(c.Breed) // own fieldOsadzone pole jest nadal dostępne po nazwie typu:
c.Animal.Name działa i jest identyczny z c.Name. Jest to potrzebne kiedy
dochodzi do kolizji.
Zastąpienie (częściowe): metoda „cieniowanie”
Jeśli typ zewnętrzny definiuje metodę o tej samej nazwie, co promowana po pierwsze, jego metoda „wygrywa”. Od wewnątrz zawsze możesz dotrzeć do osadzonego jeden poprzez nazwę typu:
func (c Dog) Greet() string {
return "BAU! " + c.Animal.Greet()
}Nie jest to dziedziczenie polimorficzne: jest to po prostu rozpoznawanie nazw leksykalnych. Do polimorfizmu używasz interfejsów (Moduł 6).
Wiele osadzań
Możesz osadzić wiele typów:
type Logger struct{ /*...*/ }
func (l Logger) Log(msg string) { /*...*/ }
type Timer struct{ /*...*/ }
func (t Timer) Now() time.Time { /*...*/ }
type Service struct {
Logger
Timer
Name string
}
s := Service{Name: "api"}
s.Log("start") // promoted from Logger
s.Now() // promoted from TimerJeśli dwa typy osadzone mają metodę o TEJ SAMEJ nazwie, dostęp bezpośredni staje się niejednoznaczne i kompilator wymaga jawnej formy (KODEF0 lub KODEF1).
Osadzanie interfejsu
Interfejsy mogą być również „wbudowane” (patrz Moduł 6):
type ReadWriter interface {
io.Reader
io.Writer
}Jest to równoważne połączeniu metod Reader i Writer.
Kiedy używać jawnej kompozycji (nie osadzania)
Jeśli chcesz mieć nazwane pole i brak automatycznej promocji, użyj zwykłego skład:
type Dog struct {
Anim Animal // NORMAL field, no promotion
Breed string
}
c.Anim.Name // you need the field nameOsadzanie to przydatne narzędzie delegowania, a nie wybór projektu ściśle lepsza niż jawna kompozycja: używaj jej, kiedy naprawdę chcesz w celu promowania interfejsu API typu wewnętrznego.
Spróbuj
Zdefiniuj psa, który osadza zwierzę (osadzanie, bez nazwy pola) i ma pole tekstowe Rasa.
Pokaż wskazówkę
Osadzanie: wpisz TYP bez nadawania mu nazwy pola.
Rozwiązanie dostępne po 3 próbach
Dodaj metodę łańcuchową Greet() do Animal i wywołaj ją bezpośrednio na zmiennej Dog (promocja metody).
Pokaż wskazówkę
Metoda zdefiniowana na Animal jest promowana do Dog dzięki osadzeniu.
Rozwiązanie dostępne po 3 próbach
Czy Go obsługuje dziedziczenie klasyczne?
type B struct { /* extends A? */ }Podsumowanie
- Brak dziedziczenia: komponujesz z osadzaniem.
- Osadzanie = zapisywanie TYPE bez nazwy pola w strukturze.
- Pola i metody typu osadzonego są promowane.
- Dostęp jawny jest zawsze dostępny:
outer.Inner.Field. - Nadpisanie „leksykalne”: metoda typu zewnętrznego przesłania metodę promowaną.
- Osadzanie ≠ is-a: dla polimorfizmu użyj interfejsów.