Go por Exemplo: Erros

No Go é idiomático comunicar erros através de um explícito, valor de retorno separado. Isso contrasta com as excessões usadas em linguagens como Java e Ruby e resultados únicos sobrecarregados / valores de erros algumas vezes usados em C. Go torna fácil ver quais funções retornam erros e o tratamento deles usando construções da mesma linguagem empregada para qualquer outra tarefa não-erro.

package main
import "errors"
import "fmt"

Por convenção, erros são o último valor de retorno e possuem o tipo error, uma interface integrada.

func f1(arg int) (int, error) {
    if arg == 42 {

errors.New constrói um valor de error básico com a mensagem de erro dada.

        return -1, errors.New(não pode trabalhar com 42")
    }

Um valor zero na posilção do erro indica que não houve erro.

    return arg + 3, nil
}

É possível usar tipos personalizados como errors através da implementação do método Error() neles. Aqui temos uma variante do exemplo acima que usa um tipo personalizado para representar explicitamente um argumento de erro.

type argError struct {
    arg  int
    prob string
}
func (e *argError) Error() string {
    return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
    if arg == 42 {

Neste caso usamos a sintaxe &argError para construir uma nova estrutura, fornecendo valores para os dois campos arg e prob.

    return -1, &argError{arg, não pode trabalhar com ele.}
    }
    return arg + 3, nil
}
func main() {

Os dois loops do teste abaixo mostram cada uma das funções retorno-erro. Note que o uso de um erro inline verificada na linha if é um idioma comum no código Go.

    for _, i := range []int{7, 42} {
        if r, e := f1(i); e != nil {
            fmt.Println("f1 falhou:", e)
        } else {
            fmt.Println("f1 funcionou:", r)
        }
    }
    for _, i := range []int{7, 42} {
        if r, e := f2(i); e != nil {
            fmt.Println("f2 falhou:", e)
        } else {
            fmt.Println("f2 funcionou:", r)
        }
    }

Se você quiser usar programaticamente dados em um erro personalizado, você precisará pegar o erro como uma instância do erro personalizado através do tipo afirmação.

    _, e := f2(42)
    if ae, ok := e.(*argError); ok {
        fmt.Println(ae.arg)
        fmt.Println(ae.prob)
    }
}
$ go run errors.go
f1 funcionou: 10
f1 falhou: não pode trabalhar com 42
f2 funcionou: 10
f2 falhou: 42 - não pode trabalhar com ele
42
não pode trabalhar com ele

Veja essa ótima postagem no blog do Go para saber mais sobre tratamento de erros.

Próximo exemplo: Goroutines.