Manejo de errores en Go
El lenguaje Go proporciona un mecanismo de manejo de errores muy simple mediante su interfaz de error integrada.
El manejo de errores en Go adopta el enfoque de devolver errores explícitamente, en lugar del mecanismo tradicional de excepciones. Este diseño hace que la lógica del código sea más clara y permite a los desarrolladores manejar errores de manera explícita en tiempo de compilación o ejecución.
El manejo de errores en Go se desarrolla principalmente en torno a los siguientes mecanismos:
errorInterfaz: representación estándar de errores.- Valor de retorno explícito: devolver errores mediante el valor de retorno de la función.
- Errores personalizados: se pueden crear errores mediante la biblioteca estándar o de forma personalizada.
panicyrecover: manejar errores graves irrecuperables.
Interfaz error
La biblioteca estándar de Go define una interfaz error, que representa una abstracción de un error.
El tipo error es un tipo de interfaz, esta es su definición:
type error interface {
Error() string
}
- Implementación
errorInterfaz: cualquier tipo que implementeError()el método puede ser usado como error. Error()El método devuelve una cadena que describe el error.
Usar el paquete errors para crear errores
En la codificación, podemos generar mensajes de error implementando el tipo de interfaz error.
Crear un error simple:
Ejemplo
import (
"errors"
"fmt"
)
func main() {
err := errors.New("this is an error")
fmt.Println(err) // Salida: this is an error
}
Las funciones suelen devolver información de error en el último valor de retorno; se puede usar errors.New para devolver un mensaje de error:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
En el siguiente ejemplo, al llamar a Sqrt pasamos un número negativo, y entonces obtenemos un objeto error no nil. Comparamos este objeto con nil, el resultado es true, por lo que se llama a fmt.Println (el paquete fmt llama al método Error al procesar errores) para mostrar el error. Vea el código de ejemplo a continuación:
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
}
Retorno explícito de errores
En Go, los errores generalmente se devuelven como valores de retorno de las funciones, y el desarrollador debe verificarlos y manejarlos explícitamente.
Retorno explícito de errores:
Ejemplo
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Salida:
Error: division by zero
Errores personalizados
Al definir tipos personalizados, se puede extender la interfaz error.
Tipo de error personalizado:
Ejemplo
import (
"fmt"
)
type DivideError struct {
Dividend int
Divisor int
}
func (e *DivideError) Error() string {
return fmt.Sprintf("cannot divide %d by %d", e.Dividend, e.Divisor)
}
func divide(a, b int) (int, error) {
if b == 0 {
return 0, &DivideError{Dividend: a, Divisor: b}
}
return a / b, nil
}
func main() {
_, err := divide(10, 0)
if err != nil {
fmt.Println(err) // Salida: cannot divide 10 by 0
}
}
El paquete fmt y el formato de errores
fmtEl paquete proporciona soporte para la salida formateada de errores:
%v: formato predeterminado.%+v: si es compatible, muestra información detallada del error.%s: se muestra como una cadena.
Ejemplo
import (
"fmt"
)
// Define una estructura DivideError
type DivideError struct {
dividee int
divider int
}
// Implementa la interfaz `error`
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// Define una función de división para el tipo `int`
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// Caso normal
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// Cuando el divisor es cero, devuelve un mensaje de error
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}
Al ejecutar el programa anterior, el resultado es:
100/10 = 10
errorMsg is:
Cannot proceed, the divider is zero.
dividee: 100
divider: 0
Usar errors.Is y errors.As
Desde Go 1.13,errorsel paquete errors introdujoerrors.Isyerrors.Aspara manejar cadenas de errores:
errors.Is
Comprueba si un error es un error específico o fue envuelto por dicho error.
Ejemplo
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("database error: %w", ErrNotFound)
}
func main() {
err := findItem(1)
if errors.Is(err, ErrNotFound) {
fmt.Println("Item not found")
} else {
fmt.Println("Other error:", err)
}
}
errors.As
Convierte el error a un tipo específico para procesarlo posteriormente.
Ejemplo
import (
"errors"
"fmt"
)
type MyError struct {
Code int
Msg string
}
func (e *MyError) Error() string {
return fmt.Sprintf("Code: %d, Msg: %s", e.Code, e.Msg)
}
func getError() error {
return &MyError{Code: 404, Msg: "Not Found"}
}
func main() {
err := getError()
var myErr *MyError
if errors.As(err, &myErr) {
fmt.Printf("Custom error - Code: %d, Msg: %s\n", myErr.Code, myErr.Msg)
}
}
panic y recover
El panic de Go se usa para manejar errores irrecuperables, y recover se usa para recuperarse de un panic.
panic:
- Hace que el programa se bloquee e imprime información de la pila.
- A menudo se usa cuando el programa no puede continuar ejecutándose.
recover:
- Capturar
panic, evitar que el programa se bloquee.
Ejemplo
import "fmt"
func safeFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong")
}
func main() {
fmt.Println("Starting program...")
safeFunction()
fmt.Println("Program continued after panic")
}
Al ejecutar el código anterior, el resultado es:
Starting program... Recovered from panic: something went wrong Program continued after panicOtras extensiones