Das error-Interface
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 52 von 107.
In Go werden Fehler über ein integriertes Interface namens error behandelt. Dieses Interface ist bemerkenswert einfach – es erfordert nur eine Methode:
type error interface {
Error() string
}Jeder Typ, der eine Error()-Methode implementiert, die einen String zurückgibt, erfüllt automatisch das error-Interface. Dies ist das Interface-System von Go in Aktion – es ist keine explizite Deklaration erforderlich.
Die gängigste Art, Fehler zu erstellen, ist die Verwendung des errors-Packages:
import "errors"
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}Go-Funktionen geben normalerweise einen Fehler als ihren letzten Rückgabewert zurück. Wenn kein Fehler auftritt, geben Sie nil zurück. Der Aufrufer prüft dann, ob der Fehler ungleich nil ist, bevor er fortfährt:
result, err := Divide(10, 0)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Result:", result)Sie können auch fmt.Errorf verwenden, um formatierte Fehlermeldungen zu erstellen:
func GetUser(id int) (string, error) {
if id <= 0 {
return "", fmt.Errorf("invalid user id: %d", id)
}
return "Alice", nil
}Dieses Muster, Fehler zurückzugeben, anstatt Exceptions zu werfen, ist grundlegend für Go. Es macht die Fehlerbehandlung explizit und zwingt dazu, zu bedenken, was passiert, wenn etwas schiefgeht – ein zentraler Aspekt beim Schreiben von robustem, objektorientiertem Code.
Aufgabe
EinfachLassen Sie uns ein Bankkontosystem erstellen, das das Fehlerbehandlungsmuster von Go demonstriert. Sie werden ein einfaches Konto erstellen, das Operationen validiert und aussagekräftige Fehler zurückgibt, wenn etwas schiefgeht.
Sie werden Ihren Code auf zwei Dateien aufteilen:
account.go: Erstellen Sie eineBankAccount-Struktur mit einem exportiertenOwner-Feld (string) und einem nicht exportiertenbalance-Feld (float64). Implementieren Sie Folgendes:NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error)- ein Konstruktor, der einen Fehler mit der Nachricht"initial deposit must be positive"zurückgibt, wenn die Ersteinzahlung null oder negativ ist. Andernfalls erstellen und geben Sie das Konto zurück.Deposit(amount float64) error- fügt dem Guthaben Geld hinzu. Geben Sie einen Fehler mit der Nachricht"deposit amount must be positive"zurück, wenn der Betrag null oder negativ ist.Withdraw(amount float64) error- hebt Geld vom Guthaben ab. Geben Sie einen Fehler mit der Nachricht"withdrawal amount must be positive"zurück, wenn der Betrag null oder negativ ist, oder"insufficient funds", wenn das Guthaben geringer als der Abhebungsbetrag ist.Balance() float64- gibt das aktuelle Guthaben zurück
main.go: Lesen Sie Kontodetails und Transaktionsbeträge aus der Eingabe. Versuchen Sie, ein Konto zu erstellen und Operationen durchzuführen. Geben Sie nach jeder Operation entweder die Erfolgsmeldung oder die Fehlermeldung aus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Name des Eigentümers
- Zeile 2: Ersteinzahlungsbetrag
- Zeile 3: Einzahlungsbetrag
- Zeile 4: Abhebungsbetrag
Geben Sie für jede Operation das Ergebnis aus:
- Nach der Kontoerstellung:
Account created for [Owner] with balance: $[balance]oderError: [error message] - Nach der Einzahlung:
Deposited successfully. New balance: $[balance]oderError: [error message] - Nach der Abhebung:
Withdrew successfully. New balance: $[balance]oderError: [error message]
Formatieren Sie alle Guthabenwerte mit zwei Dezimalstellen. Wenn die Kontoerstellung fehlschlägt, überspringen Sie die verbleibenden Operationen.
Zum Beispiel, bei Alice, 100, 50 und 200 sollte Ihre Ausgabe wie folgt aussehen:
Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient fundsUnd bei Bob, -50, 25 und 10 sollte Ihre Ausgabe wie folgt aussehen:
Error: initial deposit must be positiveSpickzettel
Go verarbeitet Fehler über das integrierte error-Interface, das eine einzige Methode erfordert:
type error interface {
Error() string
}Erstellen Sie Fehler mit dem errors-Paket:
import "errors"
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}Funktionen geben Fehler als letzten Rückgabewert zurück. Geben Sie nil zurück, wenn kein Fehler auftritt:
result, err := Divide(10, 0)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Result:", result)Verwenden Sie fmt.Errorf für formatierte Fehlermeldungen:
func GetUser(id int) (string, error) {
if id <= 0 {
return "", fmt.Errorf("invalid user id: %d", id)
}
return "Alice", nil
}Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Inhabername lesen
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// Anfangseinzahlung lesen
initialDepositStr, _ := reader.ReadString('\n')
initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)
// Einzahlungsbetrag lesen
depositStr, _ := reader.ReadString('\n')
depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)
// Auszahlungsbetrag lesen
withdrawStr, _ := reader.ReadString('\n')
withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)
// TODO: Erstelle ein neues Bankkonto mit NewBankAccount
// Wenn ein Fehler auftritt, gib "Error: [error message]" aus und beende die Funktion
// Wenn erfolgreich, gib "Account created for [Owner] with balance: $[balance]" aus
// TODO: Versuche, den Einzahlungsbetrag einzuzahlen
// Wenn ein Fehler auftritt, gib "Error: [error message]" aus
// Wenn erfolgreich, gib "Deposited successfully. New balance: $[balance]" aus
// TODO: Versuche, den Auszahlungsbetrag abzuheben
// Wenn ein Fehler auftritt, gib "Error: [error message]" aus
// Wenn erfolgreich, gib "Withdrew successfully. New balance: $[balance]" aus
// Denke daran, die Kontostandswerte mit zwei Dezimalstellen unter Verwendung von fmt.Printf("%.2f", balance) zu formatieren
_ = ownerName
_ = initialDeposit
_ = depositAmount
_ = withdrawAmount
}
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