panic-recover-go-cuando-usar

Panic en Go: cómo funciona y cuándo usarlo

  • 3 min

Un panic en Go es una interrupción brusca del flujo normal del programa. Existe, sí, pero no sustituye al manejo normal de errores.

En el artículo anterior vimos que en Go los errores son valores y que debemos gestionarlos con if err != nil. Esa es la forma civilizada de trabajar.

¿Qué pasa si el programa intenta acceder a un índice inválido o una librería detecta un estado interno imposible?

En esos casos, la goroutine entra en estado de panic y comienza a deshacer su pila de llamadas.

Vamos a ver qué ocurre durante ese proceso y cuándo tiene sentido provocar un panic de forma explícita. En el artículo siguiente veremos recover con detalle.

Qué ocurre durante un panic

Cuando ocurre un panic, el flujo normal de ejecución se detiene inmediatamente.

Se interrumpe la función actual.

Se ejecutan todas las funciones diferidas (defer) de esa función.

El pánico “burbujea” hacia arriba por la pila de llamadas (ejecutando los defer de cada nivel).

Si nadie lo recupera en esa goroutine, el programa termina y muestra la traza de la pila.

:::

Pánicos automáticos

Go lanza pánicos automáticamente ante errores de programación irrecuperables:

  • Acceder a un índice fuera de rango en un array.
  • Escribir en un mapa nil.
  • Desreferenciar un puntero nil o seleccionar uno de sus campos.
func main() {
    var slice []int
    // Esto provoca un panic runtime error: index out of range
    fmt.Println(slice[0])

    // Esta línea NUNCA se ejecutará
    fmt.Println("Fin del programa")
}
Copied!

Pánicos manuales

Nosotros también podemos pulsar el botón rojo usando la función panic(). Acepta cualquier valor (normalmente un string o un error).

func IniciarSistema() {
    if !CheckConfig() {
        // Si no hay configuración, no podemos arrancar. Abortamos.
        panic("configuración corrupta: imposible iniciar")
    }
}
Copied!

Cuándo usar panic

Este es el punto en el que los programadores de Java/C# suelen equivocarse. Ven panic/recover y piensan: “Ah, esto es throw/catch.

No lo es. En Go, usar panic para el control de flujo normal es considerado una mala práctica y un diseño pobre.

Cuándo no usarlo

  • Errores de validación: El usuario introduce mal el email. (Usa error).
  • Archivos no encontrados: (Usa error).
  • Fallos de red: (Usa error).
  • Cualquier cosa que puedas prever: Si es posible que falle, devuelve un error.

Una librería no debería entrar en pánico por una entrada inválida que pueda producirse durante el uso normal. En ese caso debe devolver un error.

Cuándo puede tener sentido

El pánico está reservado para errores verdaderamente excepcionales o bugs del programador:

  1. Inicialización que no puede fallar por diseño: las funciones Must... suelen provocar un panic cuando una constante o configuración incluida por el programador es inválida.
  2. Inconsistencia interna grave: Si tu código llega a un switch que teóricamente es imposible de alcanzar.
  3. Lógica interna acotada: algunos paquetes usan panic dentro de un algoritmo y lo convierten en error antes de cruzar la frontera pública. El llamador nunca debería verlo.

panic no debe servir para ahorrarnos un if err != nil. Para decidir qué hacer en la frontera de una goroutine existe recover, que veremos a continuación.