0Pricing
Go Academy · Lezione

Creare errori personalizzati

errors.New, fmt.Errorf ed errori sentinella

Creare errori personalizzati è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Go Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Go Academy include 4 lezioni in totale.

Perché utilizzare tipi di errore personalizzati?

I tipi di errore personalizzati contengono dati strutturati oltre a un messaggio testuale, consentendo ai chiamanti di esaminare e gestire condizioni di errore specifiche:

package main
import "fmt"

// Custom error type carries extra context
type HTTPError struct {
    StatusCode int
    Message    string
}

func (e *HTTPError) Error() string {
    return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}

func fetch(url string) error {
    return &HTTPError{404, "page not found"}
}

func main() {
    err := fetch("http://example.com")
    fmt.Println(err) // HTTP 404: page not found
}

Implementare l'interfaccia error

Qualsiasi tipo con un metodo Error() string soddisfa error:

package main
import "fmt"

type ValidationError struct {
    Field   string
    Value   interface{}
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: field %q value %v — %s", e.Field, e.Value, e.Message)
}

func validateAge(age int) error {
    if age < 0 || age > 150 {
        return &ValidationError{"age", age, "must be between 0 and 150"}
    }
    return nil
}

func main() {
    fmt.Println(validateAge(-5))
}

Errori sentinella con errors.New

Gli errori sentinella sono variabili a livello di pacchetto per condizioni di errore note:

package main
import ("fmt"; "errors")

var (
    ErrNotFound      = errors.New("not found")
    ErrUnauthorized  = errors.New("unauthorized")
    ErrAlreadyExists = errors.New("already exists")
)

func getUser(id int) (string, error) {
    if id != 1 { return "", ErrNotFound }
    return "Alice", nil
}

func main() {
    _, err := getUser(99)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("user does not exist")
    }
}

fmt.Errorf con %w per il wrapping

fmt.Errorf con %w esegue il wrapping di un errore, preservando l'originale per errors.Is ed errors.As:

package main
import ("fmt"; "errors")

var ErrDatabase = errors.New("database error")

func queryDB() error {
    return fmt.Errorf("queryDB: %w", ErrDatabase)
}

func main() {
    err := queryDB()
    fmt.Println(err)                       // queryDB: database error
    fmt.Println(errors.Is(err, ErrDatabase)) // true — unwrapped
}

Errore personalizzato con Unwrap

Implementi Unwrap() error nel tipo di errore personalizzato per partecipare alle catene di errori:

package main
import ("fmt"; "errors")

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

type QueryError struct {
    Query string
    Err   error
}

func (e *QueryError) Error() string {
    return fmt.Sprintf("query %q: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error { return e.Err }

func main() {
    err := &QueryError{"SELECT *", ErrNotFound}
    fmt.Println(err)
    fmt.Println(errors.Is(err, ErrNotFound)) // true
}

errors.Is — Controllo dell'identità

errors.Is percorre la catena degli errori cercando un errore uguale al valore di destinazione:

package main
import ("fmt"; "errors")

var ErrTimeout = errors.New("timeout")

func deepCall() error {
    return fmt.Errorf("layer3: %w", fmt.Errorf("layer2: %w", ErrTimeout))
}

func main() {
    err := deepCall()
    fmt.Println(errors.Is(err, ErrTimeout)) // true — found deep in chain
}

errors.As — Estrazione del tipo

errors.As trova nella catena il primo errore che corrisponde al tipo di destinazione e lo assegna:

package main
import ("fmt"; "errors")

type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "permission denied for " + e.User }

func action(user string) error {
    return fmt.Errorf("action: %w", &PermissionError{user})
}

func main() {
    err := action("bob")
    var pe *PermissionError
    if errors.As(err, &pe) {
        fmt.Println("denied:", pe.User) // denied: bob
    }
}

Wrapping multiplo degli errori (Go 1.20+)

Go 1.20 ha aggiunto errors.Join e fmt.Errorf con più %w per unire gli errori:

package main
import ("fmt"; "errors")

func validate(name, email string) error {
    var errs []error
    if name == ""  { errs = append(errs, errors.New("name required")) }
    if email == "" { errs = append(errs, errors.New("email required")) }
    return errors.Join(errs...)
}

func main() {
    err := validate("", "")
    fmt.Println(err)
    // name required
    // email required
}

Convenzioni per i nomi dei tipi di errore

Convenzioni per le variabili e i tipi di errore in Go:

  • Variabili di errore sentinella: ErrXxx (ad esempio ErrNotFound)
  • Tipi di errore personalizzati: XxxError (ad esempio ValidationError)
  • Una var a livello di pacchetto per gli errori sentinella, un tipo puntatore per gli errori con dati dettagliati
  • Esporti gli elementi affinché i chiamanti possano utilizzarli con errors.Is / errors.As

Quando utilizzare ciascun approccio

Scelta dell'approccio corretto per gli errori:

  • errors.New — semplice, senza dati aggiuntivi, per il controllo dell'identità di un errore sentinella
  • fmt.Errorf — messaggio formattato con wrapping opzionale
  • Tipo personalizzato — quando il chiamante ha bisogno di dati strutturati (campi, codici)
  • errors.Join — per aggregare più errori di convalida

Verifica rapida

Quale funzione consente di estrarre un tipo di errore specifico da una catena di errori?

Riepilogo: errori personalizzati

Riepilogo:

  • Implementi Error() string per creare tipi di errore personalizzati
  • Aggiunga Unwrap() error per partecipare alle catene di errori
  • Utilizzi errors.Is per i controlli di identità ed errors.As per l'estrazione del tipo
  • Errori sentinella: ErrXxx; tipi personalizzati: XxxError
  • errors.Join aggrega più errori (Go 1.20+)

Domande Frequenti

La lezione «Creare errori personalizzati» è gratuita?

Sì — il testo completo di «Creare errori personalizzati» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Go Academy, passa a CoddyKit PRO. Il corso Go Academy include 4 lezioni in totale.

Cosa imparerò in «Creare errori personalizzati»?

errors.New, fmt.Errorf ed errori sentinella Eserciti Go Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Go Academy?

Non è richiesta alcuna esperienza precedente. Go Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Creare errori personalizzati»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Go Academy?

Sì. Ogni lezione Go Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. L'interfaccia error
  2. Creare errori personalizzati
  3. Wrapping e unwrap degli errori
  4. panic, recover e defer
← Torna a Go Academy