Lezioni del modulo (5/5)
Errori: il pattern `if err != nil`
In Go gli errori sono valori, non eccezioni. Una funzione che può fallire ritorna l'errore come ultimo valore, e chi chiama lo controlla esplicitamente. È esplicito, prevedibile, facile da testare — il prezzo è un po' più di verbosità.
L'interfaccia error
error è una piccola interfaccia integrata nel linguaggio:
type error interface {
Error() string
}Qualunque tipo che implementa Error() string è un error.
Il pattern fondamentale
v, err := operazione()
if err != nil {
// gestisci o propaga
return err
}
// usa vLo vedrai migliaia di volte: è il codice idiomatico per ogni chiamata fallibile. Non sentirti in colpa per la ripetizione — è una feature, non un bug.
Costruire errori: errors.New e fmt.Errorf
import (
"errors"
"fmt"
)
err1 := errors.New("file mancante")
err2 := fmt.Errorf("apertura %q fallita: permesso negato", path)fmt.Errorf è perfetto quando vuoi includere variabili nel messaggio.
Wrapping con %w
Per propagare un errore aggiungendo contesto SENZA perdere l'originale:
f, err := os.Open(path)
if err != nil {
return fmt.Errorf("config: %w", err)
}%w "avvolge" l'errore originale, recuperabile più tardi con
errors.Is (uguaglianza per sentinel) o errors.As (per tipo concreto):
if errors.Is(err, os.ErrNotExist) {
// file inesistente, gestione speciale
}Sentinel errors
Sono errori esportati come variabili, usati per confronti con errors.Is:
var ErrNotFound = errors.New("non trovato")
func find(id int) (Item, error) {
// ...
return Item{}, ErrNotFound
}
// chiamante:
if errors.Is(err, ErrNotFound) { ... }panic e recover (cenno)
panic esiste in Go ma è riservato a errori irrecuperabili (es. bug,
invariants violati), non al normale controllo di flusso. Lo approfondiremo
nel modulo Funzioni con defer/recover. Per ora: non usarlo al posto
del pattern if err != nil.
Prova tu
Gestisci l'errore di strconv.Atoi: se err != nil, stampalo e ritorna; altrimenti stampa n.
Mostra suggerimento
Il pattern canonico: check `err != nil`, log/return, poi usa `n`.
Soluzione disponibile dopo 3 tentativi
Implementa safeDiv: se b == 0 ritorna 0 e un errors.New('divisione per zero'); altrimenti a/b e nil.
Mostra suggerimento
Controlla `b == 0` PRIMA della divisione per evitare il panic da run-time.
Soluzione disponibile dopo 3 tentativi
Quale è il pattern idiomatico per gestire un errore in Go?
v, err := f()
// poi?Recap
errorè un'interfaccia con un metodoError() string.- Pattern canonico:
v, err := f(); if err != nil { return err }. - Costruisci errori con
errors.New(msg)ofmt.Errorf("ctx: %w", err). - Usa
%wper wrapping eerrors.Is/errors.Asper ispezionare la catena. panicsolo per errori irrecuperabili, NON per il normale controllo di flusso.