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.
Aufgabe
EinfachLassen 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:
ErrItemNotFoundmit der Nachricht"item not found in inventory"ErrOutOfStockmit der Nachricht"item is out of stock"ErrInsufficientQuantitymit 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 InventarAddItem(name string, quantity int)- fügt die Menge eines Artikels hinzu oder aktualisiert sieGetQuantity(name string) (int, error)- gibt die Menge für einen Artikel zurück oderErrItemNotFound, wenn er nicht existiertPurchase(name string, quantity int) error- versucht, Artikel zu kaufen. Geben SieErrItemNotFoundzurück, wenn der Artikel nicht existiert,ErrOutOfStock, wenn die aktuelle Menge Null ist, oderErrInsufficientQuantity, wenn die angeforderte Menge den verfügbaren Bestand übersteigt. Reduzieren Sie bei Erfolg den Bestand und geben Sienilzurü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 Menge5hinzu 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 SieError: Item '[name]' does not exist in our inventoryaus - Wenn
err == ErrOutOfStock: geben SieError: Item '[name]' is currently out of stockaus - Wenn
err == ErrInsufficientQuantity: geben SieError: Cannot purchase [quantity] units of '[name]' - not enough in stockaus - 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 inventoryUnd bei laptop und 10 sollte Ihre Ausgabe wie folgt aussehen:
Error: Cannot purchase 10 units of 'laptop' - not enough in stockSpickzettel
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)
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der Go OOP
Externe DateienGo Workspace & ModulePackages & ImportsExportierte vs. nicht-exportierte NamenEinführung in OOP in GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktor-FunktionenZusammenfassung – Einfacher Taschenrechner4Interfaces
Einführung in InterfacesImplizite ImplementierungInterface als VertragLeeres Interface (any)Type AssertionType SwitchInterface-KompositionStringer & Error InterfacesRückblick - Formen-Rechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf Paket-EbeneGetter- & Setter-MethodenInformation Hiding in GoZusammenfassung - Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterType ConstraintsGenerische StructsWorkaround für generische MethodenZusammenfassung – Generische Collection2Vertiefung: Typen & Structs
Basis- & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct TagsAnonyme StructsVerschachtelte StructsZero Values & StandardwerteZusammenfassung - Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen des Struct EmbeddingMethod PromotionEinbetten mehrerer StructsEmbedding vs. AggregationShadowing eingebetteter MethodenZusammenfassung – Mitarbeiter-Hierarchie8Fehlerbehandlung & OOP
Das error-InterfaceEigene FehlertypenError Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverZusammenfassung – Datei-Parser3Zeiger & Speicher
Zeiger-Grundlagen in GoZeiger auf StructsWertübergabe vs. ReferenzübergabeDie new() FunktionGarbage Collection in GoWiederholung – Linked List Builder6Polymorphismus in Go
Polymorphismus über InterfacesDuck Typing in GoInterface-ErfüllungsregelnPolymorphe CollectionsDependency InjectionZusammenfassung – Payment Processor9Nebenläufigkeit & OOP
Goroutines GrundlagenChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignZusammenfassung - Worker Pool