Achtergrond van de vraag:
Tot Go 1.13 was een fout een eenvoudig interface. Voor extra context werden vaak eigen types gemaakt, maar er was geen gestructureerd mechanisme voor het inbedding, zoals in moderne Java of C#. Met de komst van Go 1.13 werd een standaard manier van het wikkelen (wrapping) van fouten geïntroduceerd via de functie fmt.Errorf en het identificeren van de onderliggende oorzaak (errors.Is/errors.As).
Probleem:
In complexe applicaties, waar een fout op verschillende niveaus van de stack kan optreden, is het belangrijk om de context niet te verliezen bij het teruggeven van een fout uit de diepten van de code. Anders wordt debuggen moeilijk en is het onmogelijk te begrijpen waar in de keten de fout is opgetreden.
Oplossing:
Go biedt de mogelijkheid om fouten in nieuwe foutobjecten te wikkelen die de oorzaak bevatten. Dit wordt gedaan met %w in fmt.Errorf, en voor het controleren van onderliggende oorzaken - errors.Is of errors.As uit het errors-pakket.
Codevoorbeeld:
import ( "errors" "fmt" ) var ErrNotFound = errors.New("niet gevonden") func getData() error { return fmt.Errorf("dienst database: %w", ErrNotFound) } func main() { err := getData() if errors.Is(err, ErrNotFound) { fmt.Println("Oorzaak gevonden: niet gevonden") } else { fmt.Println("Andere fout:", err) } }
Belangrijke eigenschappen:
%w voor het wikkelen van fouten via fmt.Errorf.errors.Is en errors.As.Welke formatteringsoperator is nodig voor het wikkelen van fouten via fmt.Errorf?
Het is correct om %w te gebruiken, en niet %v — alleen %w ondersteunt unwrap.
Codevoorbeeld:
fmt.Errorf("fout: %w", err)
Is het mogelijk om handmatig ketens van fouten te creëren zonder fmt.Errorf en ze nog steeds te identificeren via errors.Is?
Nee, je moet het Unwrap-interface implementeren, anders zullen de standaardfuncties de keten niet uitpakken.
Codevoorbeeld van het interface:
type wrappedError struct { msg string err error } func (w wrappedError) Error() string { return w.msg + ": " + w.err.Error() } func (w wrappedError) Unwrap() error { return w.err }
Geven fouten nil-waarden terug na wikkeling, als de geneste fout nil was?
Nee, als de geneste fout nil is, dan is de gewikkelde fout ook nil alleen bij correct gebruik. Maar als je een wrapper-structuur handmatig maakt waar het foutveld nil is, zal het niet nil zijn. Dit leidt vaak tot verwarring bij het controleren.
%w, maar alleen %v — dit verliest de mogelijkheid om de keten te analyseren.Unwrap() niet voor je eigen foutstructuren.errors.Is/As, maar vergelijk de fout alleen direct.In de applicatie werden eenvoudigweg nieuwe fouten met tekst op elk niveau teruggegeven:
return errors.New("fout bij het schrijven naar de DB")
Voordelen:
Nadelen:
Gebruikten het wikkelen van fouten met %w en analyse via errors.Is:
if errors.Is(err, ErrNotFound) { return fmt.Errorf("fout op serviceniveau: %w", err) }
Voordelen:
Nadelen: