Ricerca…


introduzione

In Go, le situazioni inaspettate vengono gestite utilizzando errori , non eccezioni. Questo approccio è più simile a quello di C, usando errno, rispetto a quello di Java o di altri linguaggi orientati agli oggetti, con i loro blocchi try / catch. Tuttavia, un errore non è un numero intero ma un'interfaccia.

Una funzione che potrebbe non riuscire in genere restituisce un errore come ultimo valore restituito. Se questo errore non è nulla , qualcosa è andato storto e il chiamante della funzione dovrebbe agire di conseguenza.

Osservazioni

Nota come in Go non si genera un errore. Invece, si restituisce un errore in caso di errore.

Se una funzione non riesce, l'ultimo valore restituito è generalmente un tipo di 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) {
}

Creazione di un valore di errore

Il modo più semplice per creare un errore è utilizzare il pacchetto errors .

errors.New("this is an error")

Se si desidera aggiungere ulteriori informazioni a un errore, il pacchetto fmt fornisce anche un utile metodo di creazione degli errori:

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

Ecco un esempio completo in cui viene restituito l'errore da una funzione:

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

Apri nel parco giochi

Creazione di un tipo di errore personalizzato

In Go, un errore è rappresentato da qualsiasi valore che può descriversi come stringa. Qualsiasi tipo che implementa l'interfaccia di error incorporata è un errore.

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

L'esempio seguente mostra come definire un nuovo tipo di errore utilizzando una stringa composita letterale.

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

Ora posso usare il mio tipo di errore personalizzato come errore:

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
}

Restituzione di un errore

In Go non si genera un errore. Invece, si restituisce un error in caso di errore.

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

Se il metodo restituisce più valori (e l'esecuzione può non riuscire), la convenzione standard restituisce l'errore come ultimo argomento.

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

Gestione di un errore

Gli errori In Go possono essere restituiti da una chiamata di funzione. La convenzione è che se un metodo può fallire, l'ultimo argomento restituito è un error .

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

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

Si utilizzano più assegnazioni di variabili per verificare se il metodo non è riuscito.

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

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

Se non ti interessa l'errore, puoi semplicemente ignorarlo assegnandolo a _ .

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

Ovviamente, ignorare un errore può avere implicazioni serie. Pertanto, questo in genere non è raccomandato.

Se si dispone di più chiamate al metodo e uno o più metodi nella catena possono restituire un errore, è necessario propagare l'errore al primo livello in grado di gestirlo.

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
}

Recupero dal panico

Un errore comune è dichiarare una sezione e iniziare a richiedere gli indici da essa senza inizializzarla, il che porta a un panico "indice fuori intervallo". Il seguente codice spiega come recuperare dal panico senza uscire dal programma, che è il comportamento normale per un panico. Nella maggior parte dei casi, restituire un errore in questo modo piuttosto che uscire dal programma in preda al panico è utile solo per scopi di sviluppo o test.

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

L'uso di una funzione separata (piuttosto che la chiusura) consente il riutilizzo della stessa funzione in altre funzioni inclini al panico.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow