En este tema, aprenderemos sobre dos mecanismos importantes en Go para el manejo de errores y situaciones excepcionales: panic y recover. Estos mecanismos permiten manejar errores de una manera controlada y segura, especialmente en situaciones críticas donde la ejecución del programa no puede continuar normalmente.

¿Qué es panic?

panic es una función incorporada en Go que se utiliza para detener la ejecución normal de un programa. Cuando se llama a panic, el programa imprime un mensaje de error y comienza a desenrollar la pila de llamadas, ejecutando las funciones defer en el camino. Finalmente, el programa se detiene.

Ejemplo de panic

package main

import "fmt"

func main() {
    fmt.Println("Inicio del programa")
    causePanic()
    fmt.Println("Fin del programa") // Esta línea no se ejecutará
}

func causePanic() {
    fmt.Println("Antes del pánico")
    panic("¡Algo salió mal!")
    fmt.Println("Después del pánico") // Esta línea no se ejecutará
}

Explicación:

  • La función causePanic llama a panic con un mensaje de error.
  • Una vez que se llama a panic, el programa imprime el mensaje de error y comienza a desenrollar la pila de llamadas.
  • Las líneas de código después de panic no se ejecutan.

¿Qué es recover?

recover es una función incorporada que permite recuperar el control de un programa que ha entrado en pánico. recover solo funciona dentro de una función defer. Si se llama a recover y no hay un pánico en curso, recover devuelve nil.

Ejemplo de recover

package main

import "fmt"

func main() {
    fmt.Println("Inicio del programa")
    safeFunction()
    fmt.Println("Fin del programa") // Esta línea se ejecutará
}

func safeFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recuperado del pánico:", r)
        }
    }()
    causePanic()
    fmt.Println("Después de causePanic") // Esta línea no se ejecutará
}

func causePanic() {
    fmt.Println("Antes del pánico")
    panic("¡Algo salió mal!")
    fmt.Println("Después del pánico") // Esta línea no se ejecutará
}

Explicación:

  • La función safeFunction utiliza defer para definir una función anónima que llama a recover.
  • Si causePanic provoca un pánico, recover captura el pánico y permite que el programa continúe ejecutándose.
  • El mensaje "Recuperado del pánico" se imprime, y el programa no se detiene abruptamente.

Ejercicio Práctico

Ejercicio 1: Manejo de Pánico en una Función

Escribe una función llamada divide que tome dos enteros y devuelva el resultado de la división. Si el divisor es cero, la función debe provocar un pánico. Luego, escribe una función safeDivide que utilice recover para manejar el pánico y devolver un error en lugar de detener el programa.

package main

import (
    "errors"
    "fmt"
)

func main() {
    result, err := safeDivide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Resultado:", result)
    }
}

func divide(a, b int) int {
    if b == 0 {
        panic("división por cero")
    }
    return a / b
}

func safeDivide(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = errors.New(fmt.Sprint(r))
        }
    }()
    result = divide(a, b)
    return
}

Explicación:

  • La función divide provoca un pánico si el divisor es cero.
  • La función safeDivide utiliza defer y recover para manejar el pánico y devolver un error en lugar de detener el programa.

Ejercicio 2: Implementación de un Servidor Web Seguro

Escribe un servidor web simple que maneje las solicitudes HTTP. Si ocurre un pánico durante el manejo de una solicitud, el servidor debe recuperarse y devolver un mensaje de error al cliente en lugar de detenerse.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", safeHandler)
    fmt.Println("Servidor escuchando en http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

func safeHandler(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if r := recover(); r != nil {
            http.Error(w, "Ocurrió un error interno", http.StatusInternalServerError)
        }
    }()
    handler(w, r)
}

func handler(w http.ResponseWriter, r *http.Request) {
    panic("¡Algo salió mal en el servidor!")
    fmt.Fprintln(w, "Hola, mundo")
}

Explicación:

  • La función safeHandler utiliza defer y recover para manejar cualquier pánico que ocurra en handler.
  • Si handler provoca un pánico, recover captura el pánico y devuelve un mensaje de error al cliente.

Conclusión

En esta sección, hemos aprendido sobre los mecanismos panic y recover en Go. panic se utiliza para manejar situaciones críticas donde la ejecución del programa no puede continuar normalmente, mientras que recover permite recuperar el control del programa y manejar el error de manera segura. Estos mecanismos son esenciales para escribir programas robustos y confiables en Go.

En el próximo módulo, exploraremos la concurrencia en Go, comenzando con las goroutines.

© Copyright 2024. Todos los derechos reservados