Fehler-Wrapping und -Unwrapping
%w, errors.Is und errors.As verwenden
Fehler-Wrapping und -Unwrapping ist eine kostenlose Go Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Go Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.
Was ist Fehler-Wrapping?
Fehler-Wrapping bettet einen ursprünglichen Fehler in einen neuen Fehler ein. Dadurch bleibt das Original zur programmgesteuerten Untersuchung erhalten, während zusätzlicher Kontext hinzugefügt wird. In Go wurde dies mit Go 1.13 offiziell eingeführt:
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
}Das Verb %w
Verwenden Sie %w (nicht %v) in fmt.Errorf, um einen Fehler zu wrappen. Auf den gewrappten Fehler kann über errors.Unwrap zugegriffen werden:
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 gibt den nächsten Fehler in der Kette (den gewrappten Fehler) oder nil zurück, wenn keiner vorhanden ist:
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 — Kette durchlaufen
errors.Is(err, target) entpackt die Fehlerkette rekursiv, bis eine Übereinstimmung gefunden wird oder nil erreicht ist:
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 — Kette nach Typen durchsuchen
errors.As(err, &target) durchläuft die Kette und sucht nach einem Fehler, der dem Typ von target zugewiesen werden kann:
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
}
}Eigenes Unwrap für Fehlerketten
Implementieren Sie Unwrap() error für Ihren eigenen Fehlertyp, damit errors.Is und errors.As unterstützt werden:
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 vs. %w in fmt.Errorf
Der Unterschied zwischen %v und %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 in der Praxis: HTTP-Handler
Konsistentes Fehler-Wrapping erleichtert das Debugging in Produktionssystemen:
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 — Mehrfaches Wrapping (Go 1.20+)
errors.Join erstellt einen Fehler, der mehrere Fehler wrapped. errors.Is prüft sie alle:
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 Practices zum Entpacken
Richtlinien für Fehler-Wrapping:
- Wrappen Sie mit
%w, damit der Fehler zur programmgesteuerten Untersuchung erhalten bleibt - Fügen Sie zur Kontextangabe den Operationsnamen hinzu:
fmt.Errorf("funcName: %w", err) - Wrappen Sie Sentinel-Fehler nicht, wenn Aufrufer
errors.Isnicht verwenden - Vermeiden Sie es, denselben Kontext auf jeder Ebene doppelt zu wrappen
- Implementieren Sie
Unwrap()für eigene Typen, damit sie an Fehlerketten teilnehmen können
Schnelltest
Was ist der Unterschied zwischen der Verwendung von %v und %w in fmt.Errorf?
Zusammenfassung: Fehler-Wrapping und -Entpacken
Zusammenfassung:
fmt.Errorf("ctx: %w", err)wrapped einen Fehler mit Kontexterrors.Unwrapgibt den nächsten Fehler in der Kette zurückerrors.Isdurchläuft die Kette auf der Suche nach einer Identitätsübereinstimmungerrors.Asdurchläuft die Kette auf der Suche nach einer Typübereinstimmung- Eigene Typen implementieren
Unwrap() error errors.Joinwrapped mehrere Fehler (Go 1.20+)
Häufig gestellte Fragen
Ist die Lektion „Fehler-Wrapping und -Unwrapping“ kostenlos?
Ja — der vollständige Text von „Fehler-Wrapping und -Unwrapping“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Go Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Fehler-Wrapping und -Unwrapping“?
%w, errors.Is und errors.As verwenden Du übst Go Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Go Academy zu starten?
Keine Vorkenntnisse erforderlich. Go Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Fehler-Wrapping und -Unwrapping“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Go Academy-Lektion Code schreiben und ausführen?
Ja. Jede Go Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Das error-Interface
- Eigene Fehler erstellen
- Fehler-Wrapping und -Unwrapping
- panic, recover und defer