Unwrapping mit `errors.As`
Teil des Abschnitts Logik & Ablauf der GO-Journey von Coddy — Lektion 41 von 68.
Während errors.Is Ihnen hilft, spezifische Fehlerwerte in einer Kette zu identifizieren, müssen Sie manchmal auf die tatsächlichen Felder und Daten eines benutzerdefinierten Fehlertyps zugreifen. Die Funktion errors.As bietet diese Möglichkeit, indem sie den ersten Fehler in einer Kette findet, der einem bestimmten Typ entspricht, und ihn zur Untersuchung extrahiert.
Die Funktion errors.As nimmt zwei Parameter entgegen: den zu untersuchenden Fehler und einen Pointer auf eine Variable des Ziel-Fehlertyps. Wenn sie einen passenden Fehlertyp in der Kette findet, setzt sie Ihre Variable auf diesen Fehler und gibt true zurück:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}Dies ist besonders leistungsfähig bei der Arbeit mit benutzerdefinierten Fehlertypen, die zusätzlichen Kontext enthalten. Im Gegensatz zu errors.Is, das nur auf Gleichheit prüft, extrahiert errors.As die tatsächliche Fehlerinstanz, was es Ihnen ermöglicht, auf deren Felder und Methoden zuzugreifen. Dies macht die Fehlerbehandlung in komplexen Anwendungen anspruchsvoller und informativer.
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 API-Fehlerbehandlungssystem, das errors.As verwendet, um benutzerdefinierte Fehlertypen aus verschachtelten Fehlerketten zu extrahieren und zu untersuchen. Diese Herausforderung zeigt, wie man errors.As einsetzt, um auf die Felder und Daten spezifischer benutzerdefinierter Fehlertypen zuzugreifen, selbst wenn diese mit zusätzlichem Kontext umschlossen (wrapped) wurden.
Sie erhalten zwei Eingaben:
- Einen String mit API-Anforderungsdetails im Format
"endpoint,method,error_code,error_field"(z. B."/users,POST,400,email") - Einen String mit Systemkontext im Format
"service_name,request_id"(z. B."UserAPI,req_12345")
Ihre Aufgabe ist es:
- Erstellen Sie einen benutzerdefinierten Fehlertyp namens
APIErrorals Struct mit drei Feldern:Code(int) - der HTTP-StatuscodeField(string) - das Feld, das den Fehler verursacht hatMessage(string) - eine Beschreibung des Fehlers
- Implementieren Sie die Methode
Error() stringfürAPIError, die Folgendes zurückgibt:"API error [code]: [message] (field: [field])" - Parsen Sie die erste Eingabe, indem Sie sie an Kommas trennen, um Endpoint, Method, Error Code und Error Field zu erhalten
- Parsen Sie die zweite Eingabe, indem Sie sie an Kommas trennen, um Service Name und Request ID zu erhalten
- Konvertieren Sie den Fehlercode-String in eine Ganzzahl (Integer)
- Erstellen Sie eine
APIError-Instanz basierend auf dem Fehlercode:- Wenn der Code 400 ist: Nachricht
"invalid request data" - Wenn der Code 401 ist: Nachricht
"authentication required" - Wenn der Code 404 ist: Nachricht
"resource not found" - Wenn der Code 500 ist: Nachricht
"internal server error" - Für jeden anderen Code: Nachricht
"unknown error"
- Wenn der Code 400 ist: Nachricht
- Erstellen Sie einen Fehler auf Endpoint-Ebene mit
fmt.Errorfund%w:"[method] [endpoint] failed: %w" - Erstellen Sie einen Fehler auf Service-Ebene:
"[service_name] request [request_id] failed: %w" - Verwenden Sie
errors.As, um denAPIErroraus der verschachtelten Fehlerkette zu extrahieren und das Ergebnis der Extraktion anzuzeigen:- Wenn die Extraktion erfolgreich ist:
"API error extracted successfully" - Wenn die Extraktion fehlschlägt:
"Failed to extract API error"
- Wenn die Extraktion erfolgreich ist:
- Wenn die Extraktion erfolgreich war, zeigen Sie die Details des extrahierten Fehlers an:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- Zeigen Sie die vollständige Fehlerkette an:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- Zeigen Sie eine abschließende Analyse an:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]"wobei error_category"Client Error"für Codes 400-499,"Server Error"für Codes 500-599 oder"Unknown"für andere Codes ist
Verwenden Sie das Paket strings, um die Eingabestrings an Kommas zu trennen, das Paket strconv, um den Fehlercode-String in einen Integer umzuwandeln, das Paket errors für errors.As und das Paket fmt für das Error-Wrapping. Diese Herausforderung zeigt, wie errors.As es Ihnen ermöglicht, auf die spezifischen Felder und Methoden benutzerdefinierter Fehlertypen innerhalb verschachtelter Fehlerketten zuzugreifen, was eine anspruchsvolle Fehlerbehandlung und -analyse ermöglicht.
Spickzettel
Die Funktion errors.As extrahiert spezifische Fehlertypen aus Fehlerketten und ermöglicht so den Zugriff auf benutzerdefinierte Fehlerfelder und -methoden.
errors.As nimmt zwei Parameter entgegen: den zu untersuchenden Fehler und einen Zeiger auf eine Variable des Ziel-Fehlertyps:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}Im Gegensatz zu errors.Is, das nur auf Gleichheit prüft, extrahiert errors.As die tatsächliche Fehlerinstanz und ermöglicht so den Zugriff auf deren Felder und Methoden für eine anspruchsvollere Fehlerbehandlung.
Probier es selbst
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Eingabe lesen
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// Eingaben parsen
apiParts := strings.Split(apiDetails, ",")
endpoint := apiParts[0]
method := apiParts[1]
errorCodeStr := apiParts[2]
errorField := apiParts[3]
contextParts := strings.Split(systemContext, ",")
serviceName := contextParts[0]
requestID := contextParts[1]
// Fehlercode in Ganzzahl umwandeln
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: Schreiben Sie Ihren Code unten
// 1. APIError-Struktur mit den Feldern Code, Field, Message erstellen
// 2. Error()-Methode für APIError implementieren
// 3. APIError-Instanz basierend auf dem Fehlercode erstellen
// 4. Eingepackte Fehler erstellen (Endpunkt-Ebene und Service-Ebene)
// 5. errors.As verwenden, um APIError aus der Kette der eingepackten Fehler zu extrahieren
// 6. Extraktionsergebnis und Fehlerdetails anzeigen
// 7. Fehlerkette und abschließende Analyse anzeigen
}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