Interfejsy Stringer i Error
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 32 z 107.
Biblioteka standardowa Go definiuje dwa interfejsy, których będziesz często używać: fmt.Stringer i error. Oba są prostymi interfejsami z jedną metodą, które zapewniają typom zaawansowaną integrację z wbudowanymi funkcjami Go.
Interfejs Stringer znajduje się w pakiecie fmt i wymaga tylko jednej metody:
type Stringer interface {
String() string
}Gdy zaimplementujesz String() dla swojego typu, funkcje takie jak fmt.Println automatycznie użyją jej do wyświetlenia wartości:
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Alice (30 lat)
}Interfejs błędu jest równie prosty i wymaga metody Error(), która zwraca ciąg znaków:
type error interface {
Error() string
}Każdy typ z metodą Error() może być użyty jako wartość błędu w Go. Dzięki temu możesz tworzyć własne typy błędów z dodatkowymi informacjami:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func main() {
err := ValidationError{Field: "email", Message: "invalid format"}
fmt.Println(err) // email: invalid format
}Te dwa interfejsy ilustrują filozofię Go: małe, skoncentrowane interfejsy, które umożliwiają potężne działanie dzięki niejawnym implementacjom.
Wyzwanie
ŁatwyStwórzmy system monitorowania temperatury, który wykorzystuje interfejsy Stringer i error, aby zapewnić czytelny wynik i sensowną obsługę błędów.
Rozmieścisz kod w dwóch plikach:
temperature.go: Utwórz strukturęTemperaturez polamiValue(float64) iUnit(string). Zaimplementuj metodęString(), aby wyświetlała temperaturę w czytelnym dla człowieka formacie. Utwórz także strukturęTemperatureErrorz polamiTemp(float64) iReason(string) oraz zaimplementuj metodęError(), aby zwracała opisowe komunikaty o błędach.main.go: Utwórz funkcję o nazwieValidateTemperature, która przyjmuje wartość typuTemperaturei zwraca błąd, jeśli temperatura jest nieprawidłowa. Temperatura jest nieprawidłowa, jeśli jest niższa od zera absolutnego (-273.15 dla Celsjusza, -459.67 dla Fahrenheita). Jeśli jest prawidłowa, funkcja zwracanil. Odczytaj dane o temperaturze z wejścia, utwórz wartość typu Temperature, sprawdź jej poprawność i wyświetl odpowiedni wynik.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Wartość temperatury (float)
- Wiersz 2: Jednostka (
Cdla Celsjusza lubFdla Fahrenheita)
Metoda String() powinna zwracać wynik w formacie:
[Value] degrees [Unit]Gdzie Unit to pełne słowo "Celsius" lub "Fahrenheit", zależnie od wejścia.
Metoda Error() powinna zwracać wynik w formacie:
invalid temperature [Temp]: [Reason]Jeśli temperatura jest prawidłowa, wyświetl Temperature za pomocą fmt.Println (które użyje Twojej metody String()). Jeśli jest nieprawidłowa, wyświetl błąd (który użyje Twojej metody Error()).
Na przykład dla wartości 25.5 i C wynik powinien być następujący:
25.5 degrees CelsiusDla wartości -500 i F wynik powinien być następujący:
invalid temperature -500: below absolute zeroUżyj "below absolute zero" jako powodu, gdy temperatura jest zbyt niska.
Spróbuj swoich sił
package main
import (
"fmt"
)
// ValidateTemperature sprawdza, czy temperatura jest prawidłowa
// Zwraca błąd, jeśli temperatura jest niższa od zera bezwzględnego
// Zero bezwzględne: -273.15 dla Celsius, -459.67 dla Fahrenheit
func ValidateTemperature(t Temperature) error {
// TODO: Zaimplementuj logikę walidacji
// Sprawdź, czy temperatura jest niższa od zera bezwzględnego, uwzględniając jednostkę
// Zwróć TemperatureError, jeśli temperatura jest nieprawidłowa, lub nil, jeśli jest prawidłowa
return nil
}
func main() {
var value float64
var unit string
fmt.Scanln(&value)
fmt.Scanln(&unit)
// TODO: Utwórz strukturę Temperature z wartościami wejściowymi
// TODO: Sprawdź poprawność temperatury za pomocą ValidateTemperature
// TODO: Jeśli wystąpi błąd, wypisz go
// W przeciwnym razie wypisz temperaturę (zostanie użyta metoda String())
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online