Sök…


Introduktion

I Go hanteras oväntade situationer med fel , inte undantag. Denna metod är mer lik den för C, som använder errno, än den för Java eller andra objektorienterade språk, med deras try / catch-block. Ett fel är dock inte ett heltal utan ett gränssnitt.

En funktion som kan misslyckas returnerar vanligtvis ett fel som dess sista returvärde. Om detta fel inte är noll , gick något fel, och den som ringer till funktionen bör vidta åtgärder i enlighet därmed.

Anmärkningar

Lägg märke till hur i Go du inte höjer ett fel. Istället returnerar du ett fel vid fel.

Om en funktion kan misslyckas är det senast returnerade värdet i allmänhet en 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) {
}

Skapa ett felvärde

Det enklaste sättet att skapa ett fel är att använda errors .

errors.New("this is an error")

Om du vill lägga till ytterligare information till ett fel ger fmt paketet också en användbar metod för att skapa fel:

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

Här är ett fullständigt exempel, där felet returneras från en funktion:

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")
}

Öppet på lekplatsen

Skapa en anpassad feltyp

I Go representeras ett fel av alla värden som kan beskriva sig själv som sträng. Varje typ som implementerar det inbyggda error är ett fel.

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

Följande exempel visar hur man definierar en ny feltyp med hjälp av en sammansatt strängbokstav.

// 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)
}

Jag kan nu använda min anpassade feltyp som fel:

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
}

Återgår ett fel

I Go tar du inte upp ett fel. Istället returnerar du ett error vid fel.

// 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
}

Om metoden returnerar flera värden (och exekveringen kan misslyckas) är standardkonventionen att returnera felet som det sista argumentet.

// 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)
}

Hantering av ett fel

I Go kan fel returneras från ett funktionssamtal. Konventionen är att om en metod kan misslyckas är det sist returnerade argumentet ett error .

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

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

Du använder flera variabla tilldelningar för att kontrollera om metoden misslyckades.

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

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

Om du inte är intresserad av felet kan du helt enkelt ignorera det genom att tilldela det till _ .

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

Naturligtvis kan ignorering av ett fel ha allvarliga konsekvenser. Därför rekommenderas detta generellt inte.

Om du har flera metodsamtal, och en eller flera metoder i kedjan kan returnera ett fel, bör du sprida felet till den första nivån som kan hantera det.

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
}

Återhämtar sig från panik

Ett vanligt misstag är att deklarera en bit och börja begära index från den utan att initialisera den, vilket leder till panik "index utanför räckvidden". Följande kod förklarar hur du återställer från paniken utan att lämna programmet, vilket är det normala beteendet för en panik. I de flesta situationer är det bara användbart för att utveckla eller testa att returnera ett fel på detta sätt snarare än att lämna programmet med panik.

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)
        }
    }
}

Användningen av en separat funktion (snarare än stängning) tillåter återanvändning av samma funktion i andra funktioner som är benägna att få panik.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow