Manejo de errores en Go: try/catch y más — nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Manejo de errores en Go: try/catch y más — nivel avanzado

\n\n

A diferencia de muchos lenguajes modernos (Java, Python, JavaScript), Go no tiene construcciones tradicionales try/catch/finally. Los desarrolladores que provienen de otros ecosistemas a menudo perciben esto como una desventaja. Sin embargo, la filosofía de Go ofrece una forma más explícita y predecible de trabajar con errores. En este artículo, analizaremos técnicas avanzadas de manejo de errores en Go: desde principios básicos hasta la creación de sistemas flexibles con panic/recover, envolturas de errores y tipos personalizados.

\n\n

1. ¿Por qué Go no tiene try/catch?

\n\n

La razón principal es la simplicidad y legibilidad del código. En Go, un error es simplemente un valor (error) que una función devuelve como último resultado. El desarrollador verifica explícitamente este valor, en lugar de depender de un flujo oculto de excepciones. Esto hace que el flujo de ejecución del programa sea evidente.

\n\n

El patrón estándar se ve así:

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n)\n\nfunc readFile(name string) ([]byte, error) {\n    data, err := os.ReadFile(name)\n    if err != nil {\n        return nil, fmt.Errorf("no se pudo leer el archivo %s: %w", name, err)\n    }\n    return data, nil\n}\n\nfunc main() {\n    data, err := readFile("config.json")\n    if err != nil {\n        fmt.Println("Error:", err)\n        return\n    }\n    fmt.Println("Datos:", string(data))\n}
\n\n

Aquí, cada error potencial se maneja explícitamente. Esto no es "ruido", sino una garantía de que el programador consideró la posible falla.

\n\n

2. Técnicas avanzadas: envolturas y cadenas de errores

\n\n

Go 1.13 introdujo soporte para envolver errores mediante %w en fmt.Errorf. Esto permite crear cadenas de errores, conservando la causa original. Para desempaquetar dichas cadenas se utilizan las funciones errors.Is y errors.As.

\n\n

Ejemplo de envoltura y verificación:

\n\n
package main\n\nimport (\n    "errors"\n    "fmt"\n)\n\nvar ErrNotFound = errors.New("registro no encontrado")\n\nfunc findUser(id int) (string, error) {\n    if id != 42 {\n        return "", fmt.Errorf("búsqueda de usuario %d: %w", id, ErrNotFound)\n    }\n    return "Alice", nil\n}\n\nfunc main() {\n    _, err := findUser(100)\n    if errors.Is(err, ErrNotFound) {\n        fmt.Println("Error: registro no encontrado. Detalle:", err)\n    } else {\n        fmt.Println("Error desconocido:", err)\n    }\n}
\n\n

Uso de errors.As para errores tipificados:

\n\n
package main\n\nimport (\n    "errors"\n    "fmt"\n)\n\ntype ValidationError struct {\n    Field string\n    Msg   string\n}\n\nfunc (e *ValidationError) Error() string {\n    return fmt.Sprintf("error de validación del campo %s: %s", e.Field, e.Msg)\n}\n\nfunc validateAge(age int) error {\n    if age < 0 {\n        return &ValidationError{Field: "age", Msg: "la edad no puede ser negativa"}\n    }\n    return nil\n}\n\nfunc main() {\n    err := validateAge(-5)\n    var ve *ValidationError\n    if errors.As(err, &ve) {\n        fmt.Printf("Campo: %s, Mensaje: %s\\n", ve.Field, ve.Msg)\n    } else {\n        fmt.Println("Error desconocido:", err)\n    }\n}
\n\n

3. Panic y Recover: recuperación de emergencia

\n\n

Aunque panic en Go es un análogo de las excepciones, solo debe usarse para situaciones verdaderamente excepcionales (por ejemplo, un error lógico del programador, división por cero, acceso fuera de los límites de un array). recover permite interceptar el pánico y reanudar la ejecución.

\n\n

Importante: recover solo funciona dentro de una función diferida (defer). Un escenario típico es un middleware en un servidor HTTP o la protección de una goroutine.

\n\n

Ejemplo de ejecución protegida de una goroutine:

\n\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\nfunc safeGoroutine(fn func()) {\n    go func() {\n                

Blogs

Book Recommendations