Go od samego początku był zbudowany wokół jawnego zwracania błędów zamiast wyjątków. Umożliwia to rozwijanie przewidywalnego kodu i unikanie ukrytych pułapek charakterystycznych dla konstrukcji try/catch w innych językach (na przykład Java lub C++). Błąd w Go to interfejs, który implementuje metodę Error(), co pozwala na tworzenie zarówno prostych, jak i złożonych/owinętych błędów z kontekstem.
Problemy pojawiają się przy niewłaściwej obsłudze błędów (na przykład, jeśli są ignorowane przez _ lub nie są owinięte dodatkowymi informacjami do debugowania) lub tworzeniu "magicznych" błędów, które nie odpowiadają interfejsowi error. Ważne jest również, aby umieć zwracać błędy z publicznych funkcji i sprawdzać je w każdym wywołaniu.
Rozwiązanie — używać standardowych podejść:
Przykład kodu:
import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s not found", e.Resource) } func GetUser(id int) (string, error) { if id != 1 { return "", &NotFoundError{"User"} } return "Steve", nil } func main() { user, err := GetUser(2) if err != nil { if nfe, ok := err.(*NotFoundError); ok { fmt.Println(nfe.Resource, "problem") } else { fmt.Println("error:", err) } } fmt.Println("user:", user) }
Kluczowe cechy:
Czy podczas obsługi błędu można porównywać przez ==, czy trzeba używać specjalnych metod?
Lepiej zawsze używać errors.Is() do porównywania z błędami-owijkami, w przeciwnym razie porównanie przez == może nie działać w przypadku istniejącej owijki błędu.
if errors.Is(err, os.ErrNotExist) { // obsługa braku pliku }
Czy obowiązkowe jest implementowanie typu-struct dla niestandardowego błędu, czy wystarczy używać errors.New("...")?
Jeśli potrzebny jest tylko tekst błędu, wystarczy errors.New(). Jeśli ważne jest zachowanie kontekstu (na przykład nazwy zasobu), lepiej zdefiniować struct z metodą Error().
Jak poprawnie zwrócić błąd w przypadku udanego wykonania funkcji?
W przypadku sukcesu zawsze zwracaj błąd nil.
return result, nil
Negatywny przypadek
Programista pisze funkcję, która zwraca błąd bez wyjaśnień (po prostu errors.New("fail")). Przy analizie logów ustalenie przyczyny jest niemożliwe.
Zalety:
Wady:
Pozytywny przypadek
Programista definiuje niestandardowy typ błędu NotFoundError i zwraca go z dokładnym opisem.
Zalety:
Wady: