Lekcje modułu (1/5)
Interfejsy: definiowanie zachowania
Interfejs w Go to zestaw sygnatur metod. Wartość
implementuje interfejs, jeśli ma wszystkie te metody — nie
implements, brak extends, brak wyraźnej rejestracji. To jest
model często nazywany „pisaniem strukturalnym” lub „statycznym pisaniem kaczym”:
kompilator sprawdza zgodność w czasie kompilacji, ale na podstawie
kształtu, a nie na deklaracjach.
Deklarowanie interfejsu
type Greeter interface {
Greet() string
}Konwencja: nazwy kończące się na -er dla interfejsów jednometodowych
(KODEF1, KODEF2, KODEF3, KODEF4). Małe interfejsy
(1–2 metody) są idiomatyczne: standardowa biblioteka jest pełna
maleńkie interfejsy, które się ze sobą łączą (io.ReadWriter,
KODEF6, …).
Niejawna implementacja
type Person struct{ Name string }
func (p Person) Greet() string {
return "ciao " + p.Name
}
// Person satisfies Greeter because it has the required method.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())Brak słowa kluczowego. Jeśli typ posiada metody, można go do niego przypisać zmienna tego typu interfejsu. To wszystko.
Polimorfizm poprzez interfejs
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }
func greet(s Greeter) {
fmt.Println(s.Greet())
}
greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})greet akceptuje dowolny typ, który spełnia wymagania Greeter. To jest droga Go
robienia polimorfizmu: żadnych hierarchii, tylko możliwości.
Pusty interfejs
var x interface{} = 42
var y any = "ciao" // any is the built-in alias of interface{}interface{} (lub any od wersji 1.18) nie wymaga żadnych metod, więc dowolnych
wartość go zaspokaja. Przydatne w przypadku kontenerów ogólnych, ale do wyodrębnienia
konkretna wartość, której potrzebujesz twierdzenie typu lub przełącznik typu
(kolejne lekcje).
Zestaw metod: wartość vs odbiornik wskaźnika (podgląd)
Przypomnij sobie z Modułu 5:
- Metody z odbiornikiem wartości znajdują się w zestawie metod zarówno
T, jak i*T. - Metody z odbiornikiem wskaźników znajdują się TYLKO w zestawie metod
*T.
Praktyczna konsekwencja:
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }
type Incrementer interface { Inc() }
var i Incrementer = &Counter{} // OK: *Counter has Inc()
// var j Incrementer = Counter{} // ERROR: Counter (value) does NOTGdy metoda ma odbiornik wskaźników, należy przypisać do niego wskaźnik zmienna interfejsu.
Spróbuj
Zdefiniuj interfejs Greeter za pomocą pojedynczego ciągu znaków metody Greet().
Pokaż wskazówkę
Składnia: `type Name interface { Method(args) return }`.
Rozwiązanie dostępne po 3 próbach
Zaimplementuj Greeter na robocie nowego typu z ciągiem identyfikacyjnym pola; metoda zwraca „bip” + ID.
Pokaż wskazówkę
Brak `implements`: po prostu zdefiniuj metodę z właściwym podpisem.
Rozwiązanie dostępne po 3 próbach
Jak zadeklarować, że typ P implementuje interfejs Greeter?
type P struct{}
// ?Podsumowanie
- Interfejs = zestaw sygnatur metod; brak KODU0.
- Niejawna implementacja: wystarczy mieć metody z właściwym podpisem.
- Idiomatyczny: małe interfejsy (1–2 metody), nazwy w
-er. interface{}/any: przyjmuje dowolną wartość, traci bezpieczeństwo typu.- Zestaw metod: odbiornik wskaźnika → tylko
*Tspełnia wymagania interfejsu. - Idź na polimorfizm: parametry typu interfejsu, bez hierarchii.