Tracks
/
Go
Go
/
Temario
/
Errores
Er

Errores en Go

2 ejercicios

Acerca de Errores

La interfaz de error

En Go, el manejo de errores no se hace mediante excepciones. En su lugar, los errores son valores normales de tipos que implementan la interfaz error integrada en el lenguaje. La interfaz error es muy sencilla. Contiene un único método Error(), que devuelve el mensaje de error como string.

type error interface {
  Error() string
}

Siempre que definas una función en la que pueda producirse un error durante la ejecución y ese error deba llegar a quien la llama, tienes que incluir error como uno de los tipos devueltos. Si la función devuelve varios valores, por convención error es siempre el último.

func DoSomething() (int, error) {
  // ...
}

Crear y devolver un error simple

No siempre tienes que implementar tú mismo la interfaz de error. Para crear un error simple, puedes usar la función errors.New(), que forma parte del paquete errors de la biblioteca estándar. Lo único que tienes que pasar es el mensaje de error como string, y errors.New() se encargará de crear un valor que contenga tu mensaje e implemente la interfaz error.

Si la función devuelve un error, es buena práctica devolver el valor cero para el resto de parámetros devueltos:

func DoSomething() (SomeStruct, int, error) {
  // ...
  return SomeStruct{}, 0, errors.New("failed to calculate result")
}
Caution

No debes dar por hecho que todas las funciones devuelven valores cero en el resto de valores devueltos cuando hay un error. Lo mejor es dar por hecho que no es seguro usar ninguno de los otros valores devueltos si se devuelve un error.

Por ejemplo, imagina una función que intentaba leer de un fichero y devuelve un slice de bytes a medio rellenar y un error. Si reutilizas ese slice de bytes devuelto en tu código, dando por hecho que siempre está vacío porque había un error, puedes encontrarte con bugs sutiles.

Las únicas excepciones son los casos en los que la documentación de la función indica claramente que los demás valores devueltos tienen sentido en caso de error. Consulta la [documentación de Write en un búfer][buffer-write] para ver un ejemplo.

Asegúrate de que el mensaje de error que proporciones sea lo más específico posible, ya que los errores no incluyen ninguna traza de pila de forma predeterminada. Por convención, el mensaje de error debe empezar con una letra minúscula y no terminar con un punto.

Si quieres usar ese error en varios sitios (o quieres poner el error a disposición de quien consuma tu paquete), deberías declarar una variable para el error en lugar de usar errors.New en línea. Por convención, el nombre de la variable debe empezar por Err o err (según si está exportada o no). A estas variables de error se las suele llamar errores centinela.

import "errors"

var ErrNotFound = errors.New("resource was not found")

func DoSomething() error {
  // ...
  return ErrNotFound
}

Devuelve nil en el error para indicar que no hubo errores durante la ejecución de la función:

func Foo() (int, error) {
  return 10, nil
}

Incluir variables en el mensaje de error

Si necesitas construir un mensaje de error más complejo a partir de algunas variables, puedes hacer uso del formato de cadenas. Go tiene una función especial, fmt.Errorf, para este propósito. Construye el string del mensaje de error y devuelve un error.

input := 123
action := "UPDATE"

err := fmt.Errorf("invalid input %d for action %s", input, action)
err.Error()
// => "invalid input 123 for action UPDATE"

Comprobar errores

Si llamas a una función que devuelve un error, lo habitual es guardar el valor del error en una variable llamada err. Antes de usar el resultado real de la función, tienes que comprobar que no hubo ningún error. Podemos usar == y != para comparar el error con nil, y sabemos que hubo un error cuando err no es nil.

Para evitar anidar el «camino feliz» de tu código, los casos de error deben gestionarse primero, normalmente mediante un retorno temprano. Consulta este famoso artículo de Mat Ryer para más detalles.

// Do this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    return err
  }
  // do something with file
}

// Not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    // handle err
  } else {
    // do something with file
  }
}

// Also not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err == nil {
    // do something with file
  }
  // handle err
}

La mayoría de las veces, el error se devolverá hacia arriba por la pila de funciones, como se muestra en el primer ejemplo de arriba. Otra forma de gestionar el error podría ser registrarlo y continuar con otra operación. Es buena práctica devolver el error o registrarlo, nunca ambas cosas.

Como la mayoría de las funciones de Go incluyen un error entre sus valores devueltos, verás y usarás el patrón if err != nil por todas partes en el código Go.

Tipos de error personalizados

Si quieres que tu error incluya más información que el simple string del mensaje de error, puedes crear un tipo de error personalizado. Como ya se ha mencionado, todo lo que implemente la interfaz error (es decir, que tenga un método Error() string) puede servir como error en Go.

Normalmente, se usa un struct para crear un tipo de error personalizado. Por convención, los nombres de los tipos de error personalizados deben terminar en Error. Además, lo mejor es definir el método Error() string con un receptor de puntero; consulta este comentario de Stack Overflow para entender el razonamiento. Ten en cuenta que esto significa que debes devolver un puntero a tu error personalizado; de lo contrario, no contará como error, porque el valor no puntero no proporciona el método Error() string.

type MyCustomError struct {
  message string
  details string
}

func (e *MyCustomError) Error() string {
  return fmt.Sprintf("%s, details: %s", e.message, e.details)
}

func someFunction() error {
  // ...
  return &MyCustomError{
    message: "...",
    details: "...",
  }
}
Editar en GitHub El enlace se abre en una nueva ventana o pestaña

Aprende Errores

La práctica está bloqueada

Desbloquea 4 ejercicios más para practicar Errores