Er

Errori in Go

2 esercizi

Informazioni su Errori

L'interfaccia di errore

In Go, la gestione degli errori non avviene tramite eccezioni. Invece, gli errori sono normali valori di tipi che implementano l'interfaccia error incorporata. L'interfaccia error è molto essenziale. Contiene un solo metodo Error() che restituisce il messaggio di errore come stringa.

type error interface {
  Error() string
}

Ogni volta che definisci una funzione in cui potrebbe verificarsi un errore durante l'esecuzione che deve raggiungere chi la chiama, devi includere error tra i tipi restituiti. Se la funzione ha più valori restituiti, per convenzione error è sempre l'ultimo.

func DoSomething() (int, error) {
  // ...
}

Creare e restituire un errore semplice

Non devi sempre implementare tu stesso l'interfaccia error. Per creare un errore semplice, puoi usare la funzione errors.New() che fa parte del pacchetto errors della libreria standard. L'unica cosa che devi passare è il messaggio di errore come stringa, e errors.New() si occuperà di creare un valore che contiene il tuo messaggio e implementa l'interfaccia error.

Se la funzione restituisce un errore, è buona pratica restituire il valore zero per tutti gli altri valori restituiti:

func DoSomething() (SomeStruct, int, error) {
  // ...
  return SomeStruct{}, 0, errors.New("failed to calculate result")
}
Caution

Non devi dare per scontato che tutte le funzioni restituiscano valori zero per gli altri valori restituiti se è presente un errore. È buona pratica presumere che non sia sicuro usare nessuno degli altri valori restituiti se viene restituito un errore.

Ad esempio, immagina che una funzione stia cercando di leggere da un file e restituisca una slice di byte riempita a metà e un errore. Se riutilizzassi quella slice di byte restituita nel tuo codice, dando per scontato che sia sempre vuota perché c'era un errore, potresti incorrere in bug subdoli.

Le uniche eccezioni sono i casi in cui la documentazione della funzione afferma chiaramente che altri valori restituiti sono significativi in caso di errore. Guarda la [documentazione di Write su un buffer][buffer-write] per un esempio.

Assicurati che il messaggio di errore che fornisci sia il più specifico possibile, poiché gli errori non includono alcuno stack trace per impostazione predefinita. Per convenzione, il messaggio di errore dovrebbe iniziare con una lettera minuscola e non terminare con un punto.

Se vuoi usare un errore del genere in più punti (o vuoi rendere l'errore disponibile a chi utilizza il tuo pacchetto), dovresti dichiarare una variabile per l'errore invece di usare errors.New in linea. Per convenzione, il nome della variabile dovrebbe iniziare con Err o err (a seconda che sia esportata o meno). Queste variabili di errore sono spesso chiamate errori sentinella.

import "errors"

var ErrNotFound = errors.New("resource was not found")

func DoSomething() error {
  // ...
  return ErrNotFound
}

Restituisci nil come errore per segnalare che non ci sono stati errori durante l'esecuzione della funzione:

func Foo() (int, error) {
  return 10, nil
}

Includere variabili nel messaggio di errore

Se devi costruire un messaggio di errore più complesso a partire da alcune variabili, puoi usare la formattazione di stringhe. Go ha una funzione speciale fmt.Errorf per questo scopo. Costruisce la stringa del messaggio di errore e restituisce un errore.

input := 123
action := "UPDATE"

err := fmt.Errorf("invalid input %d for action %s", input, action)
err.Error()
// => "invalid input 123 for action UPDATE"

Controllo degli errori

Se chiami una funzione che restituisce un errore, è comune memorizzare il valore dell'errore in una variabile chiamata err. Prima di usare il risultato effettivo della funzione, devi controllare che non ci sia stato alcun errore. Possiamo usare == e != per confrontare l'errore con nil e sappiamo che c'è stato un errore quando err non è nil.

Per evitare di annidare il «happy path» del tuo codice, i casi di errore dovrebbero essere gestiti per primi, di solito con un ritorno anticipato. Guarda questo famoso articolo di Mat Ryer per maggiori dettagli.

// Do this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    return err
  }
  // do something with file
}

// Not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    // handle err
  } else {
    // do something with file
  }
}

// Also not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err == nil {
    // do something with file
  }
  // handle err
}

Il più delle volte, l'errore verrà restituito risalendo lo stack delle funzioni come mostrato nel primo esempio sopra. Un altro modo di gestire l'errore potrebbe essere registrarlo nei log e continuare con qualche altra operazione. È buona pratica o restituire o registrare l'errore, mai entrambe le cose.

Dato che la maggior parte delle funzioni in Go include un errore tra i valori restituiti, vedrai e userai il pattern if err != nil dappertutto nel codice Go.

Tipi di errore personalizzati

Se vuoi che il tuo errore includa più informazioni della sola stringa del messaggio di errore, puoi creare un tipo di errore personalizzato. Come accennato prima, tutto ciò che implementa l'interfaccia error (cioè ha un metodo Error() string) può fungere da errore in Go.

Di solito, si usa una struct per creare un tipo di errore personalizzato. Per convenzione, i nomi dei tipi di errore personalizzati dovrebbero terminare con Error. Inoltre, è meglio definire il metodo Error() string con un ricevitore puntatore; guarda questo commento su Stack Overflow per capire il motivo. Nota che questo significa che devi restituire un puntatore al tuo errore personalizzato, altrimenti non conterà come error perché il valore non puntatore non fornisce il metodo Error() string.

type MyCustomError struct {
  message string
  details string
}

func (e *MyCustomError) Error() string {
  return fmt.Sprintf("%s, details: %s", e.message, e.details)
}

func someFunction() error {
  // ...
  return &MyCustomError{
    message: "...",
    details: "...",
  }
}
Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda

Impara Errori

La pratica è bloccata

Sblocca 4 altri esercizi per esercitarti su Errori