Menu
Coddy logo textTech

Sentinel-Fehler

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

Ein Sentinel-Error ist eine vordefinierte Fehlervariable auf Paketebene, die eine bestimmte Fehlerbedingung darstellt. Im Gegensatz zum jedesmaligen Erstellen neuer Fehler mit errors.New werden Sentinel-Errors einmal deklariert und im gesamten Code wiederverwendet.

Sie definieren Sentinel-Fehler als Variablen auf Paketebene, üblicherweise mit Namen, die mit Err beginnen:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

Funktionen geben diese vordefinierten Fehler zurück, wenn bestimmte Bedingungen eintreten:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

Die Stärke von Sentinel-Fehlern liegt darin, dass Aufrufer auf spezifische Fehlerbedingungen prüfen können, indem sie Fehlerwerte direkt vergleichen:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

Gos Standardbibliothek verwendet Sentinel-Fehler ausgiebig. Zum Beispiel signalisiert io.EOF das Ende der Eingabe, und sql.ErrNoRows weist auf ein leeres Abfrageergebnis hin. Dieses Muster schafft einen klaren Vertrag zwischen Paketen und ihren Benutzern darüber, welche Fehler zu erwarten sind.

Einfache Gleichheitsprüfungen schlagen jedoch fehl, wenn Fehler verpackt (wrapped) sind. In der nächsten Lektion lernen Sie, wie errors.Is() dieses Problem löst, indem es die gesamte Fehlerkette überprüft.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Bestandsverwaltungssystem aufbauen, das Sentinel-Errors verwendet, um spezifische Fehlerbedingungen zu kommunizieren. Sie werden Fehlervariablen auf Paketebene definieren, die Aufrufer prüfen können, um verschiedene Szenarien angemessen zu behandeln.

Sie werden Ihren Code auf zwei Dateien verteilen:

  • inventory.go: Erstellen Sie ein Inventarsystem mit vordefinierten Sentinel-Errors für häufige Fehlerfälle.

    Definieren Sie drei Sentinel-Errors auf Paketebene:

    • ErrItemNotFound mit der Nachricht "item not found in inventory"
    • ErrOutOfStock mit der Nachricht "item is out of stock"
    • ErrInsufficientQuantity mit der Nachricht "insufficient quantity available"

    Erstellen Sie ein Inventory-Struct, das eine Map von Artikelnamen zu deren Mengen enthält. Implementieren Sie diese Methoden:

    • NewInventory() *Inventory - erstellt ein leeres Inventar
    • AddItem(name string, quantity int) - fügt die Menge eines Artikels hinzu oder aktualisiert sie
    • GetQuantity(name string) (int, error) - gibt die Menge für einen Artikel zurück oder ErrItemNotFound, wenn er nicht existiert
    • Purchase(name string, quantity int) error - versucht, Artikel zu kaufen. Geben Sie ErrItemNotFound zurück, wenn der Artikel nicht existiert, ErrOutOfStock, wenn die aktuelle Menge Null ist, oder ErrInsufficientQuantity, wenn die angeforderte Menge den verfügbaren Bestand übersteigt. Reduzieren Sie bei Erfolg den Bestand und geben Sie nil zurück.
  • main.go: Lesen Sie Inventaroperationen aus der Eingabe und demonstrieren Sie, wie Aufrufer spezifische Sentinel-Errors mittels direktem Gleichheitsvergleich prüfen können.

    Lesen Sie den Artikelnamen und die Kaufmenge aus der Eingabe. Erstellen Sie ein Inventar, fügen Sie den Artikel "laptop" mit der Menge 5 hinzu und versuchen Sie dann den Kauf. Geben Sie basierend auf dem zurückgegebenen Fehler eine spezifische Nachricht aus, die zeigt, dass Sie identifiziert haben, welcher Sentinel-Error aufgetreten ist.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Name des zu kaufenden Artikels
  • Zeile 2: Zu kaufende Menge

Behandeln Sie das Ergebnis, indem Sie prüfen, welcher spezifische Fehler zurückgegeben wurde:

  • Wenn err == ErrItemNotFound: geben Sie Error: Item '[name]' does not exist in our inventory aus
  • Wenn err == ErrOutOfStock: geben Sie Error: Item '[name]' is currently out of stock aus
  • Wenn err == ErrInsufficientQuantity: geben Sie Error: Cannot purchase [quantity] units of '[name]' - not enough in stock aus
  • Bei Erfolg: geben Sie Successfully purchased [quantity] units of '[name]' aus

Zum Beispiel sollte bei laptop und 3 Ihre Ausgabe wie folgt aussehen:

Successfully purchased 3 units of 'laptop'

Und bei phone und 2 sollte Ihre Ausgabe wie folgt aussehen:

Error: Item 'phone' does not exist in our inventory

Und bei laptop und 10 sollte Ihre Ausgabe wie folgt aussehen:

Error: Cannot purchase 10 units of 'laptop' - not enough in stock

Spickzettel

Ein Sentinel-Error ist eine vordefinierte Fehlervariable auf Paketebene, die eine spezifische Fehlerbedingung darstellt. Sentinel-Errors werden einmal deklariert und im gesamten Code wiederverwendet.

Definieren Sie Sentinel-Errors als Variablen auf Paketebene, normalerweise mit Namen, die mit Err beginnen:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

Funktionen geben diese vordefinierten Fehler zurück, wenn bestimmte Bedingungen eintreten:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

Aufrufer können auf spezifische Fehlerbedingungen prüfen, indem sie Fehlerwerte direkt vergleichen:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

Die Standardbibliothek von Go verwendet Sentinel-Errors ausgiebig, wie zum Beispiel io.EOF und sql.ErrNoRows.

Probier es selbst

package main

import (
	"fmt"
)

func main() {
	// Eingabe lesen
	var itemName string
	var quantity int
	fmt.Scanln(&itemName)
	fmt.Scanln(&quantity)

	// Inventar erstellen und "laptop" mit der Menge 5 hinzufügen
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: Versuchen, den Artikel zu kaufen
	// inv.Purchase(itemName, quantity) aufrufen

	// TODO: Überprüfen, welcher spezifische Sentinel-Fehler mittels direktem Gleichheitsvergleich zurückgegeben wurde
	// if/else if-Anweisungen verwenden, um Folgendes zu prüfen:
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (Erfolg)

	// TODO: Die entsprechende Nachricht basierend auf dem Fehler ausgeben
	// Wenn ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// Wenn ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// Wenn ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// Wenn Erfolg: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
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