Go-Fehlerbehandlung
Die Sprache Go stellt über ihr eingebautes error-Interface einen sehr einfachen Mechanismus zur Fehlerbehandlung bereit.
Die Fehlerbehandlung von Go verwendet einen expliziten Ansatz zur Fehlerrückgabe statt eines traditionellen Ausnahmebehandlungsmechanismus. Dieses Design macht die Codelogik klarer und erleichtert Entwicklern die explizite Behandlung von Fehlern während der Kompilierung oder Ausführung.
Die Fehlerbehandlung von Go dreht sich hauptsächlich um die folgenden Mechanismen:
errorinterfaceDie standardmäßige Fehlerdarstellung.- Expliziter RückgabewertFehler werden über den Rückgabewert der Funktion zurückgegeben.
- Benutzerdefinierter Fehler: Fehler können über die Standardbibliothek oder auf benutzerdefinierte Weise erstellt werden.
panicundrecoverNicht behebbare fatale Fehler behandeln.
error-Schnittstelle
Die Go-Standardbibliothek definiert eine error-Schnittstelle, die eine Abstraktion eines Fehlers darstellt.
Der error-Typ ist ein Schnittstellentyp. Hier ist seine Definition:
type error interface {
Error() string
}
- Implementierung
errorinterface: Alles, was implementiertError()Jeder Typ, der die Methode Error() implementiert, kann als error verwendet werden. Error()Die Methode gibt einen String zurück, der den Fehler beschreibt.
Das errors-Paket zum Erstellen von Fehlern verwenden
Beim Programmieren können wir Fehlerinformationen generieren, indem wir den error-Schnittstellentyp implementieren.
Einen einfachen Fehler erstellen:
Beispiel
import (
"errors"
"fmt"
)
func main() {
err := errors.New("this is an error")
fmt.Println(err) // Ausgabe: this is an error
}
Funktionen geben Fehlerinformationen normalerweise als letzten Rückgabewert zurück. Sie können errors.New verwenden, um eine Fehlermeldung zurückzugeben:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
Im folgenden Beispiel übergeben wir Sqrt eine negative Zahl und erhalten dann ein Nicht-nil-Fehlerobjekt. Der Vergleich dieses Objekts mit nil ergibt true, daher wird fmt.Println aufgerufen, um den Fehler auszugeben (wenn das fmt-Paket einen Fehler behandelt, ruft es die Error-Methode auf). Siehe den Beispielaufrufcode unten:
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
}
Fehler explizit zurückgeben
In Go werden Fehler normalerweise als Rückgabewerte von Funktionen zurückgegeben, und Entwickler müssen sie explizit prüfen und behandeln.
Fehler explizit zurückgeben:
Beispiel
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Ausgabe:
Error: division by zero
Benutzerdefinierter Fehler
Durch das Definieren benutzerdefinierter Typen können Sie die error-Schnittstelle erweitern.
Benutzerdefinierte Fehlertypen:
Beispiel
import (
"fmt"
)
type DivideError struct {
Dividend int
Divisor int
}
func (e *DivideError) Error() string {
return fmt.Sprintf("kann %d nicht durch %d teilen", e.Dividend, e.Divisor)
}
func divide(a, b int) (int, error) {
if b == 0 {
return 0, &DivideError{Dividend: a, Divisor: b}
}
return a / b, nil
}
func main() {
_, err := divide(10, 0)
if err != nil {
fmt.Println(err) // Ausgabe: kann 10 nicht durch 0 teilen
}
}
Das fmt-Paket und die Fehlerformatierung.
fmtDas Paket bietet Unterstützung für die formatierte Ausgabe von Fehlern:
%v: Standardformat.%+v: Wenn unterstützt, detaillierte Fehlerinformationen anzeigen.%sAusgabe als Zeichenkette.
Beispiel
import (
"fmt"
)
// DivideError-Struktur definieren
type DivideError struct {
dividee int
divider int
}
// Das `error`-Interface implementieren
func (de *DivideError) Error() string {
strFormat := `
Kann nicht fortfahren, der Divisor ist null.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// Definiere eine Funktion für die Division vom Typ `int`
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// Normalfall
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// Gibt eine Fehlermeldung zurück, wenn der Divisor null ist
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg ist: ", errorMsg)
}
}
Führen Sie das obige Programm aus, die Ausgabe ist:
100/10 = 10
errorMsg is:
Cannot proceed, the divider is zero.
dividee: 100
divider: 0
Verwenden von errors.Is und errors.As
Ab Go 1.13,errorsDas Paket führt einerrors.Isunderrors.AsWird zur Behandlung von Fehlerketten verwendet:
errors.Is
Überprüfen Sie, ob ein Fehler ein spezifischer Fehler ist oder von diesem Fehler umschlossen wurde.
Beispiel
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("nicht gefunden")
func findItem(id int) error {
return fmt.Errorf("Datenbankfehler: %w", ErrNotFound)
}
func main() {
err := findItem(1)
if errors.Is(err, ErrNotFound) {
fmt.Println("Element nicht gefunden")
} else {
fmt.Println("Sonstiger Fehler:", err)
}
}
errors.As
Konvertieren Sie den Fehler zur weiteren Verarbeitung in einen bestimmten Typ.
Beispiel
import (
"errors"
"fmt"
)
type MyError struct {
Code int
Msg string
}
func (e *MyError) Error() string {
return fmt.Sprintf("Code: %d, Msg: %s", e.Code, e.Msg)
}
func getError() error {
return &MyError{Code: 404, Msg: "Not Found"}
}
func main() {
err := getError()
var myErr *MyError
if errors.As(err, &myErr) {
fmt.Printf("Custom error - Code: %d, Msg: %s\n", myErr.Code, myErr.Msg)
}
}
panic und recover
Gos panic wird verwendet, um nicht behebbare Fehler zu behandeln, und recover wird verwendet, um sich von einem panic zu erholen.
panic:
- Verursacht einen Programmabsturz und gibt Stack-Informationen aus.
- Wird oft verwendet, wenn das Programm nicht weiter ausgeführt werden kann.
recover:
- catch
panicProgrammabstürze vermeiden.
Beispiel
import "fmt"
func safeFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong")
}
func main() {
fmt.Println("Starting program...")
safeFunction()
fmt.Println("Program continued after panic")
}
Führen Sie den obigen Code aus, die Ausgabe ist:
Starting program... Recovered from panic: something went wrong Program continued after panicWeitere Erweiterungen