Suche…


Einführung

In Go werden unerwartete Situationen mit Fehlern und nicht mit Ausnahmen behandelt. Dieser Ansatz ist dem von C mit errno ähnlicher als der von Java oder anderen objektorientierten Sprachen mit ihren try / catch-Blöcken. Ein Fehler ist jedoch keine ganze Zahl, sondern eine Schnittstelle.

Eine Funktion, die möglicherweise fehlschlägt, gibt normalerweise einen Fehler als letzten Rückgabewert zurück. Wenn dieser Fehler nicht gleich Null ist , ist ein Fehler aufgetreten , und der Aufrufer der Funktion sollte entsprechend handeln.

Bemerkungen

Beachten Sie, wie in Go Sie keinen Fehler machen. Stattdessen kehren Sie einen Fehler im Fehlerfall.

Wenn eine Funktion fehlschlagen kann, ist der zuletzt zurückgegebene Wert im Allgemeinen ein error .

// This method doesn't fail
func DoSomethingSafe() {
}

// This method can fail
func DoSomething() (error) {
}

// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
}

Fehlerwert erstellen

Die einfachste Methode zum Erstellen eines Fehlers ist die Verwendung des errors .

errors.New("this is an error")

Wenn Sie einem Fehler zusätzliche Informationen hinzufügen möchten, bietet das fmt Paket auch eine nützliche Fehlererstellungsmethode:

var f float64
fmt.Errorf("error with some additional information: %g", f)

Hier ist ein vollständiges Beispiel, bei dem der Fehler von einer Funktion zurückgegeben wird:

package main

import (
    "errors"
    "fmt"
)

var ErrThreeNotFound = errors.New("error 3 is not found")

func main() {
    fmt.Println(DoSomething(1)) // succeeds! returns nil
    fmt.Println(DoSomething(2)) // returns a specific error message
    fmt.Println(DoSomething(3)) // returns an error variable
    fmt.Println(DoSomething(4)) // returns a simple error message
}

func DoSomething(someID int) error {
    switch someID {
    case 3:
        return ErrThreeNotFound
    case 2:
        return fmt.Errorf("this is an error with extra info: %d", someID)
    case 1:
        return nil
    }

    return errors.New("this is an error")
}

Im Spielplatz öffnen

Erstellen eines benutzerdefinierten Fehlertyps

In Go wird ein Fehler durch einen beliebigen Wert dargestellt, der sich selbst als Zeichenfolge beschreiben kann. Jeder Typ, der die integrierte error implementiert, ist ein Fehler.

// The error interface is represented by a single
// Error() method, that returns a string representation of the error
type error interface {
    Error() string
}

Das folgende Beispiel zeigt, wie Sie einen neuen Fehlertyp mithilfe eines zusammengesetzten Stringliteral definieren.

// Define AuthorizationError as composite literal
type AuthorizationError string

// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
    return string(e)
}

Ich kann jetzt meinen benutzerdefinierten Fehlertyp als Fehler verwenden:

package main

import (
    "fmt"
)

// Define AuthorizationError as composite literal
type AuthorizationError string

// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
    return string(e)
}

func main() {
    fmt.Println(DoSomething(1)) // succeeds! returns nil
    fmt.Println(DoSomething(2)) // returns an error message
}

func DoSomething(someID int) error {
    if someID != 1 {
        return AuthorizationError("Action not allowed!")
    }

    // do something here

    // return a nil error if the execution succeeded
    return nil
}

Fehler zurückgeben

In Go erheben Sie keinen Fehler. Stattdessen kehren Sie einen error im Fehlerfall.

// This method can fail
func DoSomething() error {
    // functionThatReportsOK is a side-effecting function that reports its
    // state as a boolean. NOTE: this is not a good practice, so this example
    // turns the boolean value into an error. Normally, you'd rewrite this
    // function if it is under your control.
    if ok := functionThatReportsOK(); !ok {
        return errors.New("functionThatReportsSuccess returned a non-ok state")
    }

    // The method succeeded. You still have to return an error
    // to properly obey to the method signature.
    // But in this case you return a nil error.
    return nil
}

Wenn die Methode mehrere Werte zurückgibt (und die Ausführung fehlschlagen kann), lautet die Standardkonvention, den Fehler als letztes Argument zurückzugeben.

// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
    if os.Getenv("ERROR") == "1" {
        return "", errors.New("The method failed")
    }

    s := "Success!"

    // The method succeeded.
    return s, nil
}

result, err := DoAndReturnSomething()
if err != nil {
    panic(err)
}

Fehler behandeln

In Go können Fehler von einem Funktionsaufruf zurückgegeben werden. Die Konvention ist, dass, wenn eine Methode fehlschlagen kann, das letzte zurückgegebene Argument ein error .

func DoAndReturnSomething() (string, error) {
    if os.Getenv("ERROR") == "1" {
        return "", errors.New("The method failed")
    }

    // The method succeeded.
    return "Success!", nil
}

Sie verwenden mehrere Variablenzuweisungen, um zu überprüfen, ob die Methode fehlgeschlagen ist.

result, err := DoAndReturnSomething()
if err != nil {
    panic(err)
}

// This is executed only if the method didn't return an error
fmt.Println(result)

Wenn Sie nicht an dem Fehler interessiert sind, können Sie ihn einfach ignorieren, indem Sie ihn _ zuweisen.

result, _ := DoAndReturnSomething()
fmt.Println(result)

Das Ignorieren eines Fehlers kann natürlich schwerwiegende Folgen haben. Daher wird dies generell nicht empfohlen.

Wenn Sie über mehrere Methodenaufrufe verfügen und eine oder mehrere Methoden in der Kette möglicherweise einen Fehler zurückgeben, sollten Sie den Fehler an die erste Ebene weiterleiten, die ihn behandeln kann.

func Foo() error {
    return errors.New("I failed!")    
}

func Bar() (string, error) {
    err := Foo()
    if err != nil {
        return "", err
    }

    return "I succeeded", nil
}

func Baz() (string, string, error) {
    res, err := Bar()
    if err != nil {
        return "", "", err
    }

    return "Foo", "Bar", nil
}

Sich von der Panik erholen

Ein häufiger Fehler ist das Deklarieren eines Slice und das Anfordern von Indizes ohne Initialisierung, was zu einer Panik "Index außerhalb des Bereichs" führt. Im folgenden Code wird erläutert, wie Sie die Panik beheben können, ohne das Programm zu beenden. Dies ist das normale Verhalten bei einer Panik. In den meisten Fällen ist es nur für Entwicklungs- oder Testzwecke sinnvoll, einen Fehler auf diese Weise zurückzugeben, anstatt das Programm aus Panikgründen zu beenden.

type Foo struct {
    Is []int
}

func main() {
    fp := &Foo{}
    if err := fp.Panic(); err != nil {
        fmt.Printf("Error: %v", err)
    } 
    fmt.Println("ok")
}

func (fp *Foo) Panic() (err error) {
    defer PanicRecovery(&err)
    fp.Is[0] = 5
    return nil
}

func PanicRecovery(err *error) {

    if r := recover(); r != nil {
        if _, ok := r.(runtime.Error); ok {
             //fmt.Println("Panicing")
             //panic(r)
             *err = r.(error) 
        } else {
            *err = r.(error)
        }
    }
}

Die Verwendung einer separaten Funktion (und nicht der Schließung) ermöglicht die Wiederverwendung derselben Funktion in anderen Funktionen, die zu Panik neigen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow