En Go, existe un enfoque estándar para el manejo de errores mediante la devolución de un valor de tipo error desde una función. A diferencia de los lenguajes con excepciones, en Go las excepciones (panic, recover) se utilizan solo para situaciones verdaderamente excepcionales; para la lógica de negocios, se debe usar un error común.
El método clásico:
func doSomething() error { // ... return nil // o errors.New("some error") } err := doSomething() if err != nil { // manejo de errores }
Puedes crear tipos de errores personalizados para un análisis más detallado:
type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("(%d) %s", e.Code, e.Message) } err := &MyError{404, "not found"}
Verificación típica de un error específico:
if myErr, ok := err.(*MyError); ok && myErr.Code == 404 { // manejo del error 404 }
¿Se puede comparar un error con nil usando == en Go?
Respuesta: Sí, se puede y se debe, para comprobar la ausencia de errores. Pero es importante recordar: si un error fue envuelto o creado con errores que contienen nil dentro de estructuras, la comparación puede no ser correcta. Por ejemplo:
var err error = (*MyError)(nil) fmt.Println(err == nil) // ¡falso!
El error ocurre porque la interfaz no es igual a nil si su tipo no es nil, incluso si el valor dentro es nil.
Historia
Un microservicio se ocupaba del registro de errores mediante comparación con nil. Uno de los desarrolladores devolvía un error tipado como (*MyError)(nil), sin notar que esto no es equivalente a nil (la interfaz no es nil). Como resultado, el manejo de errores dejó de funcionar, y numerosos falsos disparos aparecieron en las métricas.
Historia
En el proyecto, en lugar de transmitir errores en cadena, utilizaban panic para todos los errores, considerando esto un método "limpio". Esto llevó a que la aplicación se cayera con cada entrada no válida del usuario, ya que panic/recover no están destinados para lógica de negocios en flujo.
Historia
El error fue envuelto varias veces utilizando fmt.Errorf("some: %w", err), y al verificar un tipo de error específico se hacía una comparación normal, en lugar de usar errors.Is y errors.As. Esto provocaba que la lógica de negocios no reaccionara ante tipos de errores personalizados, aunque realmente estaban presentes dentro del error envuelto.