Go wurde von Anfang an um die explizite Rückgabe von Fehlern anstelle von Ausnahmen herum aufgebaut. Dies ermöglicht die Entwicklung von vorhersehbarem Code und vermeidet versteckte Fallen, die in try/catch-Konstruktionen anderer Sprachen (z.B. Java oder C++) vorhanden sind. Ein Fehler in Go ist ein Interface, das die Methode Error() implementiert, was die Erstellung von sowohl einfachen als auch zusammengesetzten/umschlossenen Fehlern mit Kontext ermöglicht.
Probleme treten auf, wenn Fehler nicht korrekt behandelt werden (z.B. wenn sie durch _ ignoriert oder nicht mit zusätzlichen Informationen für das Debugging umhüllt werden) oder wenn "magische" Fehler erstellt werden, die nicht dem Error-Interface entsprechen. Es ist auch wichtig, Fehler aus öffentlichen Funktionen zurückzugeben und sie bei jedem Aufruf zu überprüfen.
Die Lösung besteht darin, Standardansätze zu verwenden:
Beispielcode:
import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s nicht gefunden", e.Resource) } func GetUser(id int) (string, error) { if id != 1 { return "", &NotFoundError{"Benutzer"} } 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("Fehler:", err) } } fmt.Println("Benutzer:", user) }
Wichtige Merkmale:
Kann man beim Umgang mit error einen Vergleich über == durchführen, oder sollte man spezielle Methoden verwenden?
Es ist besser, immer errors.Is() für den Vergleich mit Fehlerwrappern zu verwenden, da der Vergleich über == möglicherweise nicht funktioniert, wenn die Fehlermeldung umhüllt ist.
if errors.Is(err, os.ErrNotExist) { // Behandlung des fehlenden Datei }
Muss man eine Struktur für einen benutzerdefinierten Fehler implementieren, oder reicht es aus, errors.New("...") zu verwenden?
Wenn nur der Fehlertext benötigt wird, reicht errors.New(). Wenn der Kontext (z.B. der Name der Ressource) wichtig ist, ist es besser, eine Struktur mit der Methode Error() zu definieren.
Wie gibt man einen Fehler bei erfolgreicher Ausführung der Funktion korrekt zurück?
Im Erfolgsfall sollte immer ein nil-Fehler zurückgegeben werden.
return result, nil
Negativer Fall
Ein Entwickler schreibt eine Funktion, die einen Fehler ohne Erläuterung zurückgibt (einfach errors.New("Fehler")). Bei der Analyse der Protokolle kann die Ursache nicht festgestellt werden.
Vorteile:
Nachteile:
Positiver Fall
Ein Entwickler definiert einen benutzerdefinierten Fehlertyp NotFoundError und gibt ihn mit einer detaillierten Beschreibung zurück.
Vorteile:
Nachteile: