Interfejsy w Go to zbiór metod, które typ musi zaimplementować, aby odpowiadać temu interfejsowi. Nie ma jawnego słowa kluczowego implements: zgodność jest strukturalna, a nie deklaratywna. Przypisanie typu realizującego do zmiennej typu interfejsowego jest możliwe tylko, jeśli typ implementuje wszystkie metody interfejsu.
Ważne: zmienna interfejsowa zawiera wskaźniki do dwóch rzeczy — na dane (value) i na typ (type).
Przykład deklaracji i realizacji:
type Printer interface { Print() } type MyPrinter struct{} func (mp MyPrinter) Print() { fmt.Println("printing...") } var p Printer = MyPrinter{} p.Print() // "printing..."
_ Co się stanie, jeśli zmienna interfejsowa jest równa nil? Czym różni się „var i interface{} = nil” od „var i interface{}”? _
Częsty błędny odpowiedź — „oba wartości są nil”. W rzeczywistości — nie:
var i interface{} = nil — zmienna jest naprawdę nil (type=nil, value=nil)var p *MyPrinter = nil; var i Printer = p, to i != nil, ponieważ type != nil (wewnątrz i — type=*MyPrinter, value=nil), a wiele sprawdzeń typu if i == nil nie zadziała, gdy się tego oczekuje.Przykład:
var p *MyPrinter = nil var i Printer = p fmt.Println(i == nil) // false!
Historia
Opis: W jednym serwisie obsługa błędów zwracała interfejs z wartością nil, a klienci uważali, że błąd jest różny od zera, wywołując zbędne działanie. Problem leżał w porównywaniu interfejsu z nil.
Historia
Opis: Podczas pisania testów omyłkowo sprawdzano błąd typu interfejsowego na równość nil po zwróceniu struktury z nil-pola. Testy nie wykrywały rzeczywistych błędów, co doprowadziło do powstania błędu w produkcji.
Historia
Opis: Podczas migracji z jednego typu interfejsowego na inny zapomniano zaimplementować wszystkie metody nowego interfejsu, ponieważ nie było jawnego implements. Kod kompilował się, ale interfejs nie był realizowany, niektóre funkcje mokujące przestały działać.