Esta pagina se ve mejor con JavaScript habilitado

Go errors

 ·  🎃 kr0m

En Go, no existe un mecanismo especial para vincular métodos directamente a los tipos de error. Los errores en Go son simplemente valores que cumplen con la interfaz error, que tiene un solo método, Error() string. Por lo tanto, cualquier tipo que implemente este método puede utilizarse como un error en Go.


Si eres nuevo en el mundo de Go te recomiendo los siguientes artículos anteriores:


Lo primero que debmos saber es que en Go el valor de error retornado por una función debe ser siempre el último, por ejemplo:

func f1(arg int) (int, error) {
    if arg == 42 {
        return -1, errors.New("can't work with 42")
    }
    return arg + 3, nil
}

Podemos programar errores custom de forma muy sencilla tan solo debemos implementar la interfaz error, que tiene un solo método, Error() string. Por lo tanto creamos una estructura con los campos que requiramos, esta estructura quedará vinculada a la función Error() debido a los Go methods de Go, acto seguido en la función f2 creamos un objeto de tipo argError pasándole como parámetros los valores esperados por la estructura:

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 {
        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}

Si no queremos mostrar el error tal cual viene de nuestra función de Error, podemos capturar el error y acceder a cada uno de los datos de la estructura, en este caso el error es capturado en la variable e y luego volcamos los campos en la variable fieldsStructure que tiene los campos definidos en la estructura argError, el segundo parámetro de retorno indica si el volcado ha sido satisfactorio o no, en caso positivo imprimimos los datos:

    _, e := f2(42)
    if fieldsStructure, ok := e.(*argError); ok {
        fmt.Println(fieldsStructure.arg)
        fmt.Println(fieldsStructure.prob)
    }

Veamos el ejemplo completo:

vi customError.go

package main

import (
    "errors"
    "fmt"
)

func f1(arg int) (int, error) {
    if arg == 42 {
        return -1, errors.New("can't work with 42")
    }
    return arg + 3, nil
}

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 {
        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}

func main() {
    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)
        }
    }
    _, e := f2(42)
    if fieldsStructure, ok := e.(*argError); ok {
        fmt.Println(fieldsStructure.arg)
        fmt.Println(fieldsStructure.prob)
    }
}

Ejecutamos el código:

go run customError.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
Si te ha gustado el artículo puedes invitarme a un RedBull aquí