Go è stato progettato sin dall'inizio attorno al ritorno esplicito degli errori anziché alle eccezioni. Questo consente di sviluppare codice prevedibile ed evitare insidie nascoste proprie delle costruzioni try/catch di altri linguaggi (ad esempio, Java o C++). Un errore in Go è un'interfaccia che implementa il metodo Error(), il che consente di creare errori sia semplici che complessi/involucrati con contesto.
I problemi sorgono quando gli errori non vengono gestiti correttamente (ad esempio, se vengono ignorati tramite _ o non vengono avvolti con informazioni aggiuntive per il debug) o nella creazione di errori "magici" che non corrispondono all'interfaccia error. È anche importante essere in grado di restituire errori dalle funzioni pubbliche e verificarli in ogni chiamata.
La soluzione è adottare approcci standard:
Esempio di codice:
import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s non trovato", e.Resource) } func GetUser(id int) (string, error) { if id != 1 { return "", &NotFoundError{"Utente"} } return "Steve", nil } func main() { user, err := GetUser(2) if err != nil { if nfe, ok := err.(*NotFoundError); ok { fmt.Println(nfe.Resource, "problema") } else { fmt.Println("errore:", err) } } fmt.Println("utente:", user) }
Caratteristiche chiave:
È possibile confrontare gli errori usando ==, o è necessario utilizzare metodi speciali?
È meglio utilizzare sempre errors.Is() per confrontare errori avvolti, altrimenti il confronto con == potrebbe non funzionare in caso di avvolgimento dell'errore.
if errors.Is(err, os.ErrNotExist) { // gestione dell'assenza del file }
È obbligatorio implementare un tipo-struct per un errore personalizzato, o è sufficiente utilizzare errors.New("...")?
Se è necessario solo il messaggio dell'errore, è sufficiente errors.New(). Se è importante mantenere il contesto (ad esempio, il nome della risorsa), è meglio definire una struct con il metodo Error().
Come restituire correttamente un errore nel caso di esecuzione riuscita della funzione?
In caso di successo, restituire sempre un errore nil.
return result, nil
Caso negativo
Uno sviluppatore scrive una funzione che restituisce un errore senza spiegazioni (solo errors.New("fail")). Analizzando i log, non è possibile determinare la causa.
Vantaggi:
Svantaggi:
Caso positivo
Uno sviluppatore definisce un tipo di errore personalizzato NotFoundError e lo restituisce con una spiegazione dettagliata.
Vantaggi:
Svantaggi: