Wrapping e unwrap degli errori
Utilizzare %w, errors.Is ed errors.As
Wrapping e unwrap degli errori è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 3 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.
Che cos'è il wrapping degli errori?
Il wrapping degli errori incorpora un errore originale in un nuovo errore, preservandolo per l'analisi programmatica e aggiungendo al contempo il contesto. È stato introdotto correttamente in Go 1.13:
package main
import ("fmt"; "errors")
var ErrDB = errors.New("database unreachable")
func queryUsers() error {
return fmt.Errorf("queryUsers: %w", ErrDB)
}
func loadProfile(id int) error {
return fmt.Errorf("loadProfile(%d): %w", id, queryUsers())
}
func main() {
err := loadProfile(42)
fmt.Println(err) // loadProfile(42): queryUsers: database unreachable
}Il verbo %w
Utilizzi %w (non %v) in fmt.Errorf per eseguire il wrapping di un errore. L'errore sottoposto a wrapping è accessibile tramite errors.Unwrap:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner error")
outer := fmt.Errorf("outer: %w", inner)
fmt.Println(outer) // outer: inner error
fmt.Println(errors.Unwrap(outer)) // inner error
fmt.Println(errors.Is(outer, inner)) // true
}errors.Unwrap
errors.Unwrap restituisce l'errore successivo nella catena, ovvero l'errore sottoposto a wrapping, oppure nil se non ce n'è alcuno:
package main
import ("fmt"; "errors")
type Layer struct{ msg string; err error }
func (l *Layer) Error() string { return l.msg }
func (l *Layer) Unwrap() error { return l.err }
func main() {
root := errors.New("root")
mid := &Layer{"mid", root}
top := &Layer{"top", mid}
fmt.Println(errors.Unwrap(top)) // mid
fmt.Println(errors.Unwrap(mid)) // root
fmt.Println(errors.Unwrap(root)) // <nil>
}errors.Is — Percorrere la catena
errors.Is(err, target) rimuove ricorsivamente il wrapping della catena degli errori finché non trova una corrispondenza o raggiunge nil:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("findItem(%d): %w",
id, fmt.Errorf("repo: %w", ErrNotFound))
}
func main() {
err := findItem(7)
fmt.Println(errors.Is(err, ErrNotFound)) // true — deep in chain
fmt.Println(err) // full message chain
}errors.As — Percorrere la catena per tipo
errors.As(err, &target) percorre la catena cercando un errore assegnabile al tipo di target:
package main
import ("fmt"; "errors")
type StatusError struct{ Code int }
func (e *StatusError) Error() string { return fmt.Sprintf("status %d", e.Code) }
func doRequest() error {
return fmt.Errorf("request: %w", &StatusError{503})
}
func main() {
err := doRequest()
var se *StatusError
if errors.As(err, &se) {
fmt.Println("status code:", se.Code) // 503
}
}Unwrap personalizzato per le catene
Implementi Unwrap() error nel tipo di errore personalizzato per supportare errors.Is ed errors.As:
package main
import ("fmt"; "errors")
type AppError struct {
Op string
Err error
}
func (e *AppError) Error() string { return fmt.Sprintf("%s: %v", e.Op, e.Err) }
func (e *AppError) Unwrap() error { return e.Err }
var ErrAuth = errors.New("unauthorized")
func main() {
err := &AppError{"login", ErrAuth}
fmt.Println(errors.Is(err, ErrAuth)) // true
}%v e %w in fmt.Errorf
La differenza tra %v e %w:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner")
withV := fmt.Errorf("outer: %v", inner) // string only, no wrap
withW := fmt.Errorf("outer: %w", inner) // wraps inner
fmt.Println(errors.Is(withV, inner)) // false — not wrapped
fmt.Println(errors.Is(withW, inner)) // true — wrapped
}Wrapping nella pratica: gestore HTTP
Un wrapping coerente degli errori facilita il debug nei sistemi di produzione:
package main
import "fmt"
func dbQuery(sql string) error {
return fmt.Errorf("db.Query(%q): connection refused", sql)
}
func getUserByID(id int) (string, error) {
if err := dbQuery("SELECT * FROM users WHERE id=?"); err != nil {
return "", fmt.Errorf("getUserByID(%d): %w", id, err)
}
return "Alice", nil
}
func handler() error {
_, err := getUserByID(1)
if err != nil {
return fmt.Errorf("handler: %w", err)
}
return nil
}
func main() { fmt.Println(handler()) }errors.Join — Wrapping multiplo (Go 1.20+)
errors.Join crea un errore che esegue il wrapping di più errori. errors.Is li controlla tutti:
package main
import ("fmt"; "errors")
var ErrA = errors.New("err A")
var ErrB = errors.New("err B")
func main() {
joined := errors.Join(ErrA, ErrB)
fmt.Println(joined)
fmt.Println(errors.Is(joined, ErrA)) // true
fmt.Println(errors.Is(joined, ErrB)) // true
}Best practice per il wrapping degli errori
Linee guida per il wrapping degli errori:
- Esegua il wrapping con
%wper preservare l'errore e consentirne l'analisi programmatica - Aggiunga il nome dell'operazione come contesto:
fmt.Errorf("funcName: %w", err) - Non esegua il wrapping degli errori sentinella se i chiamanti non utilizzeranno
errors.Is - Eviti di aggiungere due volte lo stesso contesto a ogni livello
- Implementi
Unwrap()nei tipi personalizzati per partecipare alle catene
Verifica rapida
Qual è la differenza tra l'utilizzo di %v e %w in fmt.Errorf?
Riepilogo: wrapping e unwrapping degli errori
Riepilogo:
fmt.Errorf("ctx: %w", err)esegue il wrapping con contestoerrors.Unwraprecupera l'errore successivo nella catenaerrors.Ispercorre la catena per cercare una corrispondenza di identitàerrors.Aspercorre la catena per cercare una corrispondenza di tipo- I tipi personalizzati implementano
Unwrap() error errors.Joinesegue il wrapping di più errori (Go 1.20+)
Domande Frequenti
La lezione «Wrapping e unwrap degli errori» è gratuita?
Sì — il testo completo di «Wrapping e unwrap degli errori» è 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 «Wrapping e unwrap degli errori»?
Utilizzare %w, errors.Is ed errors.As 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 3 di 4.
Quanto tempo richiede la lezione «Wrapping e unwrap degli errori»?
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
- L'interfaccia error
- Creare errori personalizzati
- Wrapping e unwrap degli errori
- panic, recover e defer