Go by Example: Errors

En Go es idiomático comunicar errores a través de un valor de retorno explícito y separado. Esto contrasta con las excepciones usadas en lenguajes como Java y Ruby y el valor único sobrecargado de resultado / error a veces utilizado en C. El enfoque de Go facilita ver qué funciones devuelven errores y manejarlos usando los mismos constructos del lenguaje empleados para cualquier otra tarea no relacionada con errores.

package main
import (
    "errors"
    "fmt"
)

Por convención, los errores son el último valor de retorno y tienen el tipo error, una interfaz incorporada.

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

errors.New() construye un valor básico de error con el mensaje de error dado.

        return -1, errors.New("can't work with 42")
    }

Un valor nil en la posición del error indica que no hubo error.

    return arg + 3, nil
}

Es posible usar tipos personalizados como errors implementando el método Error() en ellos. Aquí hay una variante del ejemplo anterior que usa un tipo personalizado para representar explícitamente un error de argumento.

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 {

En este caso, usamos la sintaxis &argError para construir una nueva estructura, suministrando valores para los dos campos arg y prob.

        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}
func main() {

Los dos bucles a continuación prueban cada una de nuestras funciones que devuelven errores. Observa que el uso de una verificación de error en la línea del if es un idiomatismo común en el código de Go.

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

Si quieres usar programáticamente los datos en un error personalizado, necesitarás obtener el error como una instancia del tipo de error personalizado mediante una afirmación de tipo.

    _, e := f2(42)
    if ae, ok := e.(*argError); ok {
        fmt.Println(ae.arg)
        fmt.Println(ae.prob)
    }
}
$ go run errors.go
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it

Consulta este excelente artículo en el blog de Go para más información sobre el manejo de errores.

Siguiente ejemplo: Goroutines.