ProgrammatieBackend ontwikkelaar

Vertel me hoe de foutafhandeling werkt met het package error wrapping in Go: wat is error wrapping, waarom is het belangrijk en hoe implementeer je foutwraps correct?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

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:

  • Gebruik van %w voor het wikkelen van fouten via fmt.Errorf.
  • Identificatie van geneste foutoorzaken via errors.Is en errors.As.
  • Compatibiliteit met aangepaste fouttypes bij inbedding en unwrap.

Vragen met een valstrik.

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.

Typische fouten en anti-patronen

  • Gebruik geen %w, maar alleen %v — dit verliest de mogelijkheid om de keten te analyseren.
  • Implementeer Unwrap() niet voor je eigen foutstructuren.
  • Doe geen controle via errors.Is/As, maar vergelijk de fout alleen direct.
  • Maak nieuwe fouten zonder oorzaak (verlies van context).

Voorbeeld uit het leven

Negatieve case

In de applicatie werden eenvoudigweg nieuwe fouten met tekst op elk niveau teruggegeven:

return errors.New("fout bij het schrijven naar de DB")

Voordelen:

  • Eenvoudig en snel.

Nadelen:

  • Het is onmogelijk om te onderscheiden dat de fout eigenlijk "niet gevonden" is uit de diepte, en brak de zakelijke logica bovenaan.
  • Verlies van informatie over de stack en de bron van de fout.

Positieve case

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:

  • De oorzaak wordt correct bepaald op elk niveau.
  • Eenvoudiger om te debuggen, de originele context is altijd zichtbaar.

Nadelen:

  • Vereist begrip van hoe wrapping werkt en gekwalificeerd foutbeheer.