Menu
Coddy logo textTech

Error Wrapping (fmt.Errorf)

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 54 von 107.

Wenn Fehler mehrere Schichten Ihrer Anwendung durchlaufen, wird es entscheidend zu wissen, wo ein Fehler seinen Ursprung hat. Die fmt.Errorf-Funktion von Go mit dem Verb %w ermöglicht es Ihnen, Fehler zu verpacken, wodurch der ursprüngliche Fehler erhalten bleibt, während Kontext hinzugefügt wird.

Error Wrapping erzeugt eine Kette von Fehlern. Jede Ebene kann Informationen darüber hinzufügen, was sie gerade versuchte, als der Fehler auftrat:

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // Daten verarbeiten...
    return nil
}

Das %w-Verb ist speziell – es verpackt den ursprünglichen Fehler innerhalb des neuen. Dies unterscheidet sich von %v, das den Fehler lediglich in einen String umwandelt und die Identität des ursprünglichen Fehlers verliert.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

Wenn LoadSettings fehlschlägt, zeigt die Fehlermeldung die vollständige Kette an: "loading settings: reading config file: open settings.json: no such file or directory". Jede Ebene fügt Kontext hinzu, was das Debugging erheblich erleichtert.

Der umschlossene Fehler enthält immer noch den ursprünglichen Fehler in seinem Inneren. In der nächsten Lektion lernst du, wie du diese Fehler entpackst und mit errors.Is() und errors.As() überprüfst, was sich darin befindet.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Auftragsverarbeitungssystem erstellen, das das Error Wrapping über mehrere Ebenen hinweg demonstriert. Sie werden eine Kette von Funktionen erstellen, bei der jede Ebene Kontext zu Fehlern hinzufügt, was es einfach macht, genau zu verfolgen, wo Probleme auftreten.

Sie werden Ihren Code auf zwei Dateien verteilen:

  • orders.go: Erstellen Sie die Logik zur Auftragsverarbeitung mit mehreren Ebenen, die Fehler beim Aufsteigen in der Hierarchie einpacken (wrap).

    Implementieren Sie drei Funktionen, die eine Verarbeitungskette bilden:

    • ValidateItem(itemID string) error - Gibt einen Fehler mit der Nachricht "item not found" zurück, wenn die itemID "INVALID" ist, andernfalls wird nil zurückgegeben.
    • ProcessOrder(orderID, itemID string) error - Ruft ValidateItem auf. Wenn ein Fehler zurückgegeben wird, verpacken Sie diesen mit dem Kontext: "processing order [orderID]: %w". Andernfalls geben Sie nil zurück.
    • SubmitOrder(customerName, orderID, itemID string) error - Ruft ProcessOrder auf. Wenn ein Fehler zurückgegeben wird, verpacken Sie diesen mit dem Kontext: "submitting order for [customerName]: %w". Andernfalls geben Sie nil zurück.

    Jede Ebene sollte fmt.Errorf mit dem Verb %w verwenden, um den Fehler der darunter liegenden Ebene einzupacken und so eine Kette von Kontexten aufzubauen.

  • main.go: Lesen Sie die Bestelldetails aus der Eingabe ein, rufen Sie SubmitOrder auf und zeigen Sie das Ergebnis an. Wenn ein Fehler auftritt, geben Sie die vollständige Fehlerkette aus. Wenn der Vorgang erfolgreich ist, geben Sie eine Bestätigungsmeldung aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Kundenname
  • Zeile 2: Bestell-ID
  • Zeile 3: Artikel-ID

Geben Sie das Ergebnis aus:

  • Wenn ein Fehler auftritt: Error: [full error chain]
  • Bei Erfolg: Order [orderID] submitted successfully for [customerName]

Zum Beispiel, gegeben Alice, ORD-123 und INVALID, sollte Ihre Ausgabe wie folgt aussehen:

Error: submitting order for Alice: processing order ORD-123: item not found

Beachten Sie, wie die Fehlermeldung die vollständige Kette anzeigt – Sie können das Problem vom Übermittlungsversuch auf oberster Ebene über die Auftragsverarbeitung bis hin zum eigentlichen Validierungsfehler zurückverfolgen. Jede Ebene hat ihren eigenen Kontext mit %w hinzugefügt.

Und gegeben Bob, ORD-456 und ITEM-001, sollte Ihre Ausgabe wie folgt aussehen:

Order ORD-456 submitted successfully for Bob

Spickzettel

Verwenden Sie fmt.Errorf mit dem Verb %w, um Fehler zu wrappen und dabei den ursprünglichen Fehler beizubehalten:

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    return nil
}

Das Verb %w wrappt den ursprünglichen Fehler innerhalb des neuen, im Gegensatz zu %v, das den Fehler nur in einen String umwandelt und die Identität des ursprünglichen Fehlers verliert.

Error-Wrapping erzeugt eine Kette, in der jede Ebene Kontext hinzufügt:

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

Die resultierende Fehlermeldung zeigt die vollständige Kette: "loading settings: reading config file: open settings.json: no such file or directory"

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Kundennamen lesen
	scanner.Scan()
	customerName := scanner.Text()
	
	// Bestell-ID lesen
	scanner.Scan()
	orderID := scanner.Text()
	
	// Artikel-ID lesen
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: SubmitOrder mit den Eingabewerten aufrufen
	// TODO: Wenn ein Fehler auftritt, ausgeben: Error: [full error chain]
	// TODO: Wenn erfolgreich, ausgeben: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung