Vai al contenuto
eLearner.app
Modulo 6 · Lezione 5 di 530/50 nel corso~14 min
Lezioni del modulo (5/5)

L’interfaccia error

error in Go non è una keyword: è un'interfaccia built-in con un solo metodo.

Go
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

Go
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:

Go
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:

Go
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

Go
if err := find("k"); err != nil {
    return fmt.Errorf("operazione X: %w", err)
}

%w (NON %s%v) crea un nuovo errore che avvolge quello originale, mantenendo la catena navigabile da errors.Is/As.

Pattern di gestione

Go
v, err := op()
if err != nil {
    return fmt.Errorf("op fallita per %q: %w", id, err)
}

Idiomi:

  • Controlla err != nil subito, 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

Esercizio#go.m6.l5.e1
Tentativi: 0Caricamento…

Implementa Error() string su *ErrNotFound in modo che ritorni 'non trovato: <Key>'.

Caricamento editor…
Mostra suggerimento

`fmt.Println(err)` chiama automaticamente il metodo Error() della tua struct.

Soluzione disponibile dopo 3 tentativi

Esercizio#go.m6.l5.e2
Tentativi: 0Caricamento…

Usa errors.Is per controllare se err è uguale alla sentinella ErrVuoto.

Caricamento editor…
Mostra suggerimento

`errors.Is(err, target)` è robusto anche con catene di wrapping.

Soluzione disponibile dopo 3 tentativi

Quiz#go.m6.l5.e3
Pronto

Qual è la firma esatta del metodo per implementare error?

Go
func (e *MyErr) ??? {}
Opzioni di risposta

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 / %s per wrappare: usa SEMPRE %w.