In Go is er een standaardbenadering voor foutafhandeling door een waarde van het type error uit een functie terug te geven. In tegenstelling tot talen met uitzonderingen, worden in Go uitzonderingen (panic, recover) alleen gebruikt voor werkelijk uitzonderlijke situaties; voor bedrijfslogica dient een normale fout gebruikt te worden.
De klassieke manier:
func doSomething() error { // ... return nil // of errors.New("some error") } err := doSomething() if err != nil { // foutverwerking }
Je kunt eigen fouttypen maken voor een gedetailleerdere analyse:
type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("(%d) %s", e.Code, e.Message) } err := &MyError{404, "not found"}
Typische controle van een specifieke fout:
if myErr, ok := err.(*MyError); ok && myErr.Code == 404 { // verwerking van fout 404 }
Kun je een error met nil vergelijken met behulp van == in Go?
Antwoord: Ja, dat kan en dat moet, om de afwezigheid van een fout te controleren. Maar het is belangrijk om te onthouden: als de error gewikkeld is of gemaakt met fouten die nil bevatten binnen structuren, kan de vergelijking onjuist zijn. Bijvoorbeeld:
var err error = (*MyError)(nil) fmt.Println(err == nil) // false!
De fout ligt erin dat het interface niet gelijk is aan nil als zijn type niet nil is, zelfs als de waarde binnen nil is.
Verhaal
Een microservice was bezig met het loggen van fouten door vergelijking met nil. Een van de ontwikkelaars gaf een getypeerde fout terug zoals (*MyError)(nil), zonder te beseffen dat dit niet gelijk is aan nil (interface is niet nil). Als gevolg hiervan stopte de foutverwerking met werken, en vele valse waarschuwingen belandden in de metrics.
Verhaal
In het project werd in plaats van het doorgeven van de fout via de keten, panic gebruikt voor alle fouten, in de veronderstelling dat dit een “schone” manier was. Dit leidde tot het vastlopen van de applicatie bij elke ongeldige gebruikersinvoer, aangezien panic/recover niet bedoeld zijn voor stroom bedrijfslogica.
Verhaal
De fout was meerdere keren gewikkeld met fmt.Errorf("some: %w", err), en bij het controleren van een specifiek type fout werd een normale vergelijking gemaakt, in plaats van gebruik te maken van errors.Is en errors.As. Dit leidde ertoe dat de bedrijfslogica niet reageerde op aangepaste fouttypen, hoewel deze daadwerkelijk aanwezig waren in de gewikkelde fout.