Module lessons (5/5)
Errors: the `if err != nil` pattern
In Go, errors are values, not exceptions. A function that can fail returns the error as the last value, and the caller checks it explicitly. It is explicit, predictable, easy to test — the price is a bit more verbosity.
The error interface
error is a small interface built into the language:
type error interface {
Error() string
}Any type that implements Error() string is an error.
The fundamental pattern
v, err := operazione()
if err != nil {
// gestisci o propaga
return err
}
// usa vYou will see this thousands of times: it is the idiomatic code for every fallible call. Do not feel guilty about the repetition — it is a feature, not a bug.
Building errors: errors.New and fmt.Errorf
import (
"errors"
"fmt"
)
err1 := errors.New("file mancante")
err2 := fmt.Errorf("apertura %q fallita: permesso negato", path)fmt.Errorf is perfect when you want to include variables in the message.
Wrapping with %w
To propagate an error adding context WITHOUT losing the original:
f, err := os.Open(path)
if err != nil {
return fmt.Errorf("config: %w", err)
}%w "wraps" the original error, recoverable later with
errors.Is (equality for sentinels) or errors.As (for concrete type):
if errors.Is(err, os.ErrNotExist) {
// file inesistente, gestione speciale
}Sentinel errors
These are errors exported as variables, used for comparisons with errors.Is:
var ErrNotFound = errors.New("non trovato")
func find(id int) (Item, error) {
// ...
return Item{}, ErrNotFound
}
// chiamante:
if errors.Is(err, ErrNotFound) { ... }panic and recover (preview)
panic exists in Go but is reserved for unrecoverable errors (e.g. bugs,
violated invariants), not for normal control flow. We will go deeper in
the Functions module with defer/recover. For now: do not use it in place
of the if err != nil pattern.
Try it
Handle the error from strconv.Atoi: if err != nil, print it and return; otherwise print n.
Show hint
The canonical pattern: check `err != nil`, log/return, then use `n`.
Solution available after 3 attempts
Implement safeDiv: if b == 0 return 0 and an errors.New('divisione per zero'); otherwise a/b and nil.
Show hint
Check `b == 0` BEFORE the division to avoid the run-time panic.
Solution available after 3 attempts
Which is the idiomatic pattern to handle an error in Go?
v, err := f()
// poi?Recap
erroris an interface with one methodError() string.- Canonical pattern:
v, err := f(); if err != nil { return err }. - Build errors with
errors.New(msg)orfmt.Errorf("ctx: %w", err). - Use
%wfor wrapping anderrors.Is/errors.Asto inspect the chain. paniconly for unrecoverable errors, NOT for normal control flow.