ProgrammatieGo ontwikkelaar

Wat zijn de kenmerken van foutafhandeling (errors) in Go, hoe maak je fouten op de juiste manier en verwerk je deze, en hoe implementeer je eigen fouttypes?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

Go is vanaf het begin gebouwd rond het expliciete retourneren van fouten in plaats van uitzonderingen. Dit stelt ontwikkelaars in staat om voorspelbare code te schrijven en te voorkomen dat ze onzichtbare valkuilen tegenkomen die typisch zijn voor try/catch-constructies van andere talen (zoals Java of C++). Een fout in Go is een interface die de Error()-methode implementeert, wat het mogelijk maakt om zowel eenvoudige als samengestelde/omhulde fouten met context te creëren.

Problemen ontstaan bij onjuiste foutafhandeling (bijvoorbeeld als ze worden genegeerd via _ of niet worden omhulld met extra informatie voor debugging) of het maken van "magische" fouten die niet voldoen aan de error-interface. Het is ook belangrijk om fouten terug te geven uit openbare functies en ze bij elke aanroep te controleren.

Oplossing — gebruik standaardbenaderingen:

  • Altijd de fout als laatste waarde van de functie retourneren.
  • Gebruik errors.New, fmt.Errorf om fouten te creëren.
  • Voor gebruikersfouten, maak je eigen types die Error() implementeren.
  • Voor complexe gevallen kun je foutomhulsel (errors.Wrap) toepassen om de context niet te verliezen.

Voorbeeldcode:

import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s niet gevonden", 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, "probleem") } else { fmt.Println("fout:", err) } } fmt.Println("gebruiker:", user) }

Belangrijke kenmerken:

  • Fouten worden altijd expliciet geretourneerd, meestal als laatste argument van de functie.
  • Voor complexe fouten kunnen eigen types (struct) worden gedefinieerd die de interface error implementeren.
  • Voor het omhulden van fouten en het behouden van de stack trace kan het pakket "errors" worden gebruikt (Go 1.13+ ondersteunt errors.Is en errors.As voor het werken met foutketens).

Vragen met een valstrik.

Kun je bij het verwerken van een fout vergelijken met ==, of moet je speciale methodes gebruiken?

Het is beter om altijd errors.Is() te gebruiken voor vergelijking met foutomhulsel, anders kan de vergelijking met == niet werken bij het hebben van een omhulsel van de fout.

if errors.Is(err, os.ErrNotExist) { // verwerking van ontbrekend bestand }

Is het verplicht om een type-structuur te implementeren voor een aangepaste fout, of is het voldoende om errors.New("...") te gebruiken?

Als alleen de fouttekst nodig is, is errors.New() voldoende. Als het belangrijk is om de context te behouden (bijvoorbeeld de naam van de hulpbron), is het beter om een struct te definiëren met de Error()-methode.

Hoe moet je een fout correct retourneren in het geval van een succesvolle functie-uitvoering?

Bij succes moet je altijd een nil-fout retourneren.

return result, nil

Typische fouten en anti-patronen

  • Het negeren van geretourneerde fouten (door middel van _ of het overslaan van verwerking)
  • Vergelijken van fouten alleen met ==, ondanks geneste fouten
  • Hardcoded strings in plaats van fouten
  • Ontbreken van extra context in fouten

Voorbeeld uit het leven

Negatieve case

Een ontwikkelaar schrijft een functie die een fout retourneert zonder uitleg (gewoon errors.New("fail")). Bij het analyseren van logs is het niet mogelijk om de oorzaak vast te stellen.

Voordelen:

  • Snelheid van implementatie

Nadelen:

  • Oninformatieve fouten
  • Moeilijkheid bij debugging

Positieve case

Een ontwikkelaar definieert een aangepaste typefout NotFoundError en retourneert deze met een gedetailleerde beschrijving.

Voordelen:

  • Gemak bij het filteren van logs
  • Gemakkelijkheid in het zoeken en verwerken van fouten

Nadelen:

  • Behoefte aan het beschrijven van extra structuren