Unwrapping mit `errors.Is`
Teil des Abschnitts Logik & Ablauf der GO-Journey von Coddy — Lektion 40 von 68.
Beim Arbeiten mit verschachtelten Fehlern benötigen Sie eine Möglichkeit zu prüfen, ob ein bestimmter Fehler irgendwo in der Fehlerkette existiert. Die Funktion errors.Is bietet genau diese Funktionalität und ermöglicht es Ihnen, Sentinel-Fehler zu identifizieren, selbst wenn diese mehrfach verschachtelt wurden.
Die Funktion errors.Is nimmt zwei Parameter entgegen: den Fehler, den Sie untersuchen möchten, und den Ziel-Fehler, nach dem Sie suchen. Sie gibt true zurück, wenn der Ziel-Fehler irgendwo in der Fehlerkette gefunden wird:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}Dies ist die moderne, empfohlene Methode, um in Go auf spezifische Fehler zu prüfen. Im Gegensatz zu String-Vergleichen oder direkten Gleichheitsprüfungen funktioniert errors.Is korrekt mit gewrappten Fehlern und folgt der Fehlerkette, um Übereinstimmungen zu finden. Dies macht Ihre Fehlerbehandlung robust und zuverlässig, selbst wenn Fehler mehrere Schichten Ihrer Anwendung durchlaufen.
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Aufgabe
EinfachErstellen Sie ein Datenbankverbindungs-Überwachungssystem, das errors.Is verwendet, um spezifische Verbindungsfehler in verschachtelten Fehlerketten (wrapped error chains) zu identifizieren. Diese Herausforderung zeigt, wie man errors.Is einsetzt, um Sentinel-Fehler zu erkennen, selbst wenn diese durch mehrere Anwendungsschichten mit zusätzlichem Kontext umschlossen wurden.
Sie erhalten zwei Eingaben:
- Einen String mit Details zur Datenbankoperation im Format
"database_name,operation,error_type"(z. B."users_db,connect,connection_timeout") - Einen String mit dem Anwendungskontext im Format
"service_name,retry_count"(z. B."AuthService,3")
Ihre Aufgabe ist es:
- Definieren Sie drei Sentinel-Fehler mit
errors.New():ErrConnectionTimeoutmit der Nachricht"connection timeout"ErrConnectionRefusedmit der Nachricht"connection refused"ErrDatabaseNotFoundmit der Nachricht"database not found"
- Parsen Sie die erste Eingabe, indem Sie sie an den Kommas trennen, um Datenbankname, Operation und Fehlertyp zu erhalten
- Parsen Sie die zweite Eingabe, indem Sie sie an den Kommas trennen, um Servicename und Anzahl der Versuche (retry count) zu erhalten
- Erstellen Sie den ursprünglichen Fehler basierend auf dem Fehlertyp:
- Wenn der Fehlertyp
"connection_timeout"ist: verwenden SieErrConnectionTimeout - Wenn der Fehlertyp
"connection_refused"ist: verwenden SieErrConnectionRefused - Wenn der Fehlertyp
"database_not_found"ist: verwenden SieErrDatabaseNotFound - Für jeden anderen Fehlertyp: verwenden Sie
errors.New("unknown database error")
- Wenn der Fehlertyp
- Erstellen Sie einen verschachtelten Fehler auf Datenbankebene mit
fmt.Errorfund%w:"failed to [operation] database [database_name]: %w" - Erstellen Sie einen verschachtelten Fehler auf Serviceebene:
"[service_name] database operation failed after [retry_count] retries: %w" - Verwenden Sie
errors.Is, um zu prüfen, ob der finale verschachtelte Fehler mit jedem Sentinel-Fehler übereinstimmt, und geben Sie die Ergebnisse aus:"Checking for connection timeout: [true/false]""Checking for connection refused: [true/false]""Checking for database not found: [true/false]"
- Geben Sie die Fehlerkette aus:
"Error Chain:""Original: [original_error_message]""Database level: [database_level_error_message]""Service level: [service_level_error_message]"
- Geben Sie die Fehleranalyse aus:
"Error Analysis:""Database: [database_name]""Operation: [operation]""Service: [service_name]""Retries: [retry_count]""Error type detected: [detected_error_type]"wobei detected_error_type einer der Werte "Connection Timeout", "Connection Refused", "Database Not Found" oder "Unknown Error" ist
Verwenden Sie das strings-Paket, um die Eingabestrings an den Kommas zu trennen, das errors-Paket für Sentinel-Fehler und errors.Is, sowie das fmt-Paket für das Error-Wrapping. Diese Herausforderung zeigt, wie errors.Is eine robuste Fehleridentifizierung ermöglicht, die korrekt mit verschachtelten Fehlern funktioniert, was für eine zuverlässige Fehlerbehandlung in komplexen Anwendungen unerlässlich ist.
Spickzettel
Die Funktion errors.Is prüft, ob ein bestimmter Fehler irgendwo in einer Fehlerkette existiert, selbst wenn er mehrfach verschachtelt (wrapped) ist:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}errors.Is nimmt zwei Parameter entgegen: den zu untersuchenden Fehler und den zu suchenden Zielfehler. Sie gibt true zurück, wenn der Zielfehler irgendwo in der Fehlerkette gefunden wird.
Dies ist die moderne, empfohlene Methode, um in Go auf spezifische Fehler zu prüfen, da sie im Gegensatz zu String-Vergleichen oder direkten Gleichheitsprüfungen korrekt mit verschachtelten Fehlern funktioniert.
Probier es selbst
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// Eingabe lesen
var dbOperation string
var appContext string
fmt.Scanln(&dbOperation)
fmt.Scanln(&appContext)
// Eingaben parsen
dbParts := strings.Split(dbOperation, ",")
databaseName := dbParts[0]
operation := dbParts[1]
errorType := dbParts[2]
contextParts := strings.Split(appContext, ",")
serviceName := contextParts[0]
retryCount := contextParts[1]
// TODO: Schreiben Sie Ihren Code unten
// 1. Definieren Sie die drei Sentinel-Fehler mit errors.New()
// 2. Erstellen Sie den ursprünglichen Fehler basierend auf dem Fehlertyp
// 3. Erstellen Sie einen auf Datenbankebene gewrappten Fehler mit fmt.Errorf und %w
// 4. Erstellen Sie einen auf Serviceebene gewrappten Fehler
// 5. Verwenden Sie errors.Is, um auf jeden Sentinel-Fehler zu prüfen
// 6. Zeigen Sie die Ergebnisse und die Fehlerkette an
}Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Logik & Ablauf
1Fortgeschrittener Kontrollfluss
Switch mit `fallthrough`Abbrechen von verschachtelten SchleifenFortsetzen einer bestimmten SchleifeDie `goto`-AnweisungZusammenfassung – Fortgeschrittene Schleifensteuerung4Projekt: Einfache Aufgabenliste
Projekt-SetupEine Aufgabe hinzufügen7Fehlerbehandlung im Detail
Benutzerdefinierte FehlertypenFehler-Wrapping mit `%w`Unwrapping mit `errors.Is`Unwrapping mit `errors.As``panic` verstehen`recover` verwendenZusammenfassung – Sichere Division2Structs und Methoden
Methoden für Structs definierenValue ReceiverPointer ReceiverReceiver auswählenMethoden vs. FunktionenZusammenfassung – Struct-Verhalten5Maps im Detail
Maps von StructsPointer als Map-WertePrüfen auf Nil-MapsMaps vergleichenZusammenfassung – Wortfrequenz-Zähler8Projekt: Einfache Bestandsverwaltung
ProjektübersichtLagerbestand prüfen11Abschlussherausforderungen
Einfache KontaktlisteEinfacher Zahlen-ValidatorSammler für eindeutige Elemente3Interfaces (Die Grundlagen)
Was ist ein Interface?Ein Interface definierenEin Interface implementierenInterface-Typen verwendenLeeres InterfaceType AssertionsType SwitchZusammenfassung – Formen und Verhalten