Lezioni del modulo (5/5)
L’interfaccia error
error in Go non è una keyword: è un'interfaccia built-in con un
solo metodo.
type error interface {
Error() string
}Tutto ciò che ha Error() string è un error. Combinato con la
convenzione di ritornare (T, error) dalle funzioni, è il fondamento
della gestione degli errori in Go.
Errori sentinella
import "errors"
var ErrNotFound = errors.New("non trovato")
func find(key string) (string, error) {
// ...
return "", ErrNotFound
}Una sentinella è un valore error esportato che il chiamante può
confrontare per riconoscere uno specifico caso d'errore.
Errori custom (con dati)
Per portare contesto (es. la chiave che mancava) si definisce un tipo:
type ErrNotFound struct {
Key string
}
func (e *ErrNotFound) Error() string {
return "non trovato: " + e.Key
}
func find(key string) (string, error) {
return "", &ErrNotFound{Key: key}
}errors.Is e errors.As (Go 1.13+)
Confrontare con == funziona solo per sentinelle "pure". Per essere
robusto a errori wrappati, usa il pacchetto errors:
import "errors"
if errors.Is(err, ErrNotFound) {
// err È ErrNotFound (anche se wrappato)
}
var nfe *ErrNotFound
if errors.As(err, &nfe) {
// err È (o wrappa) un *ErrNotFound; nfe punta al valore concreto
fmt.Println("chiave mancante:", nfe.Key)
}errors.Is(err, target): vero se nella catena di wrapping c'è target.errors.As(err, &target): assegna a target il primo errore della catena del suo tipo.
Wrapping con %w
if err := find("k"); err != nil {
return fmt.Errorf("operazione X: %w", err)
}%w (NON %s né %v) crea un nuovo errore che avvolge quello
originale, mantenendo la catena navigabile da errors.Is/As.
Pattern di gestione
v, err := op()
if err != nil {
return fmt.Errorf("op fallita per %q: %w", id, err)
}Idiomi:
- Controlla
err != nilsubito, niente "early happy path". - Aggiungi contesto a ogni livello con
fmt.Errorf("... : %w", err). - A "monte" (vicino al main / handler), discrimina con
errors.Is/As.
Prova tu
Implementa Error() string su *ErrNotFound in modo che ritorni 'non trovato: <Key>'.
Mostra suggerimento
`fmt.Println(err)` chiama automaticamente il metodo Error() della tua struct.
Soluzione disponibile dopo 3 tentativi
Usa errors.Is per controllare se err è uguale alla sentinella ErrVuoto.
Mostra suggerimento
`errors.Is(err, target)` è robusto anche con catene di wrapping.
Soluzione disponibile dopo 3 tentativi
Qual è la firma esatta del metodo per implementare error?
func (e *MyErr) ??? {}Recap
error = interface { Error() string }, built-in.- Sentinelle con
errors.New("...")per casi noti senza contesto. - Tipi-errore custom con campi per portare contesto.
errors.Is(err, target): confronto robusto al wrapping.errors.As(err, &target): estrazione del tipo concreto.fmt.Errorf("...: %w", err): wrapping che preserva la catena.- Mai
%v/%sper wrappare: usa SEMPRE%w.