Definiowanie i implementowanie interfejsów
Niejawna zgodność i pusty interfejs
Definiowanie i implementowanie interfejsów to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.
Czym jest interfejs?
Interfejs w Go to zbiór sygnatur metod. Każdy typ, który implementuje wszystkie te metody, niejawnie spełnia interfejs — nie jest potrzebne słowo kluczowe implements. Nazywa się to typowaniem strukturalnym lub typowaniem kaczym.
Deklarowanie interfejsu
Zdefiniuj interfejs za pomocą słowa kluczowego type:
package main
import "fmt"
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * 3.14159 * c.Radius }
func main() {
var s Shape = Circle{5}
fmt.Printf("Area: %.2f\n", s.Area())
}Niejawne spełnianie interfejsu
Nie jest potrzebna żadna deklaracja intencji. Jeśli typ ma właściwe metody, automatycznie spełnia interfejs:
package main
import "fmt"
type Greeter interface{ Greet() string }
type English struct{}
func (e English) Greet() string { return "Hello" }
type Spanish struct{}
func (s Spanish) Greet() string { return "Hola" }
func say(g Greeter) { fmt.Println(g.Greet()) }
func main() {
say(English{})
say(Spanish{})
}Pusty interfejs
interface{} (lub any w Go 1.18+) jest spełniany przez każdy typ. Używa się go, gdy typ jest nieznany w czasie kompilacji:
package main
import "fmt"
func printAny(v any) { fmt.Printf("%T: %v\n", v, v) }
func main() {
printAny(42)
printAny("hello")
printAny([]int{1,2,3})
}Wartości interfejsów
Wartość interfejsu przechowuje dwie rzeczy: konkretny typ i konkretną wartość. Pusty interfejs ma oba te elementy ustawione na nil:
package main
import "fmt"
type Animal interface{ Sound() string }
type Dog struct{}
func (d Dog) Sound() string { return "woof" }
func main() {
var a Animal
fmt.Println(a == nil) // true
a = Dog{}
fmt.Println(a == nil) // false
fmt.Println(a.Sound())
}Spełnianie wielu interfejsów
Typ może jednocześnie spełniać wiele interfejsów:
package main
import "fmt"
type Reader interface{ Read() string }
type Writer interface{ Write(string) }
type ReadWriter interface{ Reader; Writer }
type File struct{ content string }
func (f *File) Read() string { return f.content }
func (f *File) Write(s string) { f.content = s }
func main() {
var rw ReadWriter = &File{}
rw.Write("hello")
fmt.Println(rw.Read())
}Przypisywanie interfejsów
Szerszy interfejs może przechowywać węższą wartość konkretnego typu. Przypisywanie między typami interfejsów wymaga, aby konkretny typ spełniał oba interfejsy:
package main
import "fmt"
type Stringer interface{ String() string }
type Point struct{ X, Y int }
func (p Point) String() string { return fmt.Sprintf("(%d,%d)", p.X, p.Y) }
func main() {
var s Stringer = Point{3, 4}
fmt.Println(s.String())
}Pułapka pustego interfejsu
Interfejs, który nie jest nil, a przechowuje konkretną wartość nil, NIE jest równy nil:
package main
import "fmt"
type MyErr struct{}
func (e *MyErr) Error() string { return "oops" }
func bad() error {
var e *MyErr // nil pointer
return e // returns non-nil interface!
}
func main() {
err := bad()
fmt.Println(err == nil) // false — common gotcha
}Interfejsy ułatwiają testowanie
Zdefiniowanie zależności jako interfejsów umożliwia zastępowanie rzeczywistych implementacji atrapami w testach:
package main
import "fmt"
type EmailSender interface{ Send(to, body string) error }
type MockSender struct{ Sent []string }
func (m *MockSender) Send(to, body string) error {
m.Sent = append(m.Sent, to)
return nil
}
func notify(s EmailSender, addr string) { s.Send(addr, "hello") }
func main() {
mock := &MockSender{}
notify(mock, "a@b.com")
fmt.Println(mock.Sent) // [a@b.com]
}Przyjmuj interfejsy, zwracaj struktury
Najlepsza praktyka w Go: parametry funkcji powinny być interfejsami (dla elastyczności), a typy zwracane powinny być konkretne (aby wywołujący wiedzieli, co otrzymują):
package main
type Logger interface{ Log(string) }
type FileLogger struct{}
func (f *FileLogger) Log(s string) {}
func NewFileLogger() *FileLogger { // returns concrete
return &FileLogger{}
}
func process(l Logger) {} // accepts interface
func main() { process(NewFileLogger()) }Utrzymuj małe interfejsy
Biblioteka standardowa Go preferuje niewielkie interfejsy: io.Reader ma jedną metodę, podobnie jak io.Writer. Małe interfejsy można łatwiej łączyć i zastępować atrapami.
Szybkie sprawdzenie
Czy typ musi zadeklarować, że implementuje interfejs?
Podsumowanie: interfejsy
Najważniejsze informacje:
- Interfejsy definiują zachowanie, a nie dane
- Spełnianie interfejsu jest niejawne — nie ma słowa kluczowego
implements - Pusty interfejs (
any) akceptuje każdy typ - Uważaj na pułapkę pustego interfejsu o wartości nil
- Utrzymuj interfejsy małe i skoncentrowane
Polecenie ćwiczeniowe
Zdefiniuj interfejs Storage z metodami Save(key, value string) error i Load(key string) (string, error). Zaimplementuj go za pomocą MemStorage opartego na mapie i przetestuj.
Często zadawane pytania
Czy lekcja „Definiowanie i implementowanie interfejsów” jest bezpłatna?
Tak — pełny tekst „Definiowanie i implementowanie interfejsów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Definiowanie i implementowanie interfejsów”?
Niejawna zgodność i pusty interfejs Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Go Academy?
Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Definiowanie i implementowanie interfejsów”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?
Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Definiowanie i implementowanie interfejsów
- Podstawowe interfejsy biblioteki standardowej
- Asercje typów i przełączniki typów
- Kompozycja interfejsów i dobre praktyki