← Go EspañolChapter 10 of 13

Manejo de Errores

## Objetivos de Aprendizaje - Comprender la filosofía de manejo de errores de Go - Trabajar con la interface error - Crear errores personalizados - Manejar errores efectivamente - Usar panic y recover apropiadamente ## Filosofía de Errores de Go Go usa retornos de error explícitos en lugar de excepciones. ```go result, err := riskyOperation() if err != nil { // Manejar error } ``` ## La Interface error ```go type error interface { Error() string } ``` ### Error Básico ```go import "errors" func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("división por cero") } return a / b, nil } ``` ## Creando Errores ### errors.New ```go import "errors" err := errors.New("algo salió mal") fmt.Println(err) // algo salió mal ``` ### fmt.Errorf ```go import "fmt" err := fmt.Errorf("entrada inválida: %s", "valor faltante") ``` ### Tipos de Error Personalizados ```go type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("%s: %s", e.Field, e.Message) } func validate(name string) error { if name == "" { return &ValidationError{Field: "name", Message: "no puede estar vacío"} } return nil } ``` ### Envoltura de Errores (Go 1.13+) ```go import "fmt" func readConfig(path string) error { err := os.Open(path) if err != nil { return fmt.Errorf("falló al abrir config: %w", err) } return nil } ``` ### Unwrap ```go import "errors" err := readConfig("missing.txt") if err != nil { // Verificar error original if os.IsNotExist(err) { fmt.Println("El archivo no existe") } // Cadena de unwrap for err != nil { fmt.Println(err) err = errors.Unwrap(err) } } ``` ## Manejando Errores ### Patrón Básico ```go result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Resultado:", result) ``` ### Retorno Anticipado ```go func process(data string) error { file, err := os.Open(data) if err != nil { return err // Retorno anticipado en error } defer file.Close() // Continuar procesamiento... return nil } ``` ### Múltiples Errores ```go func processAll(files []string) error { for _, file := range files { if err := process(file); err != nil { return fmt.Errorf("procesando %s: %w", file, err) } } return nil } ``` ## Patrones de Verificación de Errores ### Errores Centinela ```go import "errors" import "os" var ErrNotFound = errors.New("recurso no encontrado") func find(id string) (string, error) { if id == "missing" { return "", ErrNotFound } return "encontrado", nil } if err := find("missing"); err != nil { if errors.Is(err, ErrNotFound) { fmt.Println("Recurso no encontrado") } } ``` ### errors.Is ```go import "errors" err := find("missing") if errors.Is(err, ErrNotFound) { // Manejar no encontrado } ``` ### errors.As ```go type CustomError struct { Code int Msg string } func (e *CustomError) Error() string { return e.Msg } var cerr *CustomError if errors.As(err, &cerr) { fmt.Printf("Código de error personalizado: %d\n", cerr.Code) } ``` ## Funciones Comunes de Error ### Errores de os ```go import "os" file, err := os.Open("missing.txt") if err != nil { os.IsNotExist(err) // true si el archivo no existe os.IsPermission(err) // true si permiso denegado os.IsExist(err) // true si el archivo ya existe } ``` ### Errores de net ```go import "net" _, err := net.Dial("tcp", "localhost:9999") if err != nil { var opErr *net.OpError if errors.As(err, &opErr) { fmt.Println("Operación:", opErr.Op) } } ``` ## Manejo de Errores Personalizado ### Manejador de Error ```go type Handler func(error) func handle(h Handler, err error) { if err != nil { h(err) } } ``` ### Patrón de Reintento ```go func withRetry(maxRetries int, fn func() error) error { var err error for i := 0; i < maxRetries; i++ { err = fn() if err == nil { return nil } time.Sleep(time.Duration(i+1) * time.Second) } return fmt.Errorf("después de %d reintentos: %w", maxRetries, err) } ``` ## panic y recover ### Cuándo Usar panic - Reservado para situaciones verdaderamente irrecuperables - Errores de programación (puntero nil, fuera de límites) - No para condiciones de error esperadas ### panic ```go func main() { panic("¡algo malo pasó!") fmt.Println("Esto no se ejecutará") } ``` ### recover ```go func safeCall() { defer func() { if r := recover(); r != nil { fmt.Println("Recuperado de:", r) } }() panic("¡Algo salió mal!") fmt.Println("Esto no se ejecutará") } func main() { safeCall() fmt.Println("El programa continúa...") } ``` ### Recover en Defer ```go func mayPanic() { panic("¡panic!") } func main() { defer func() { if r := recover(); r != nil { fmt.Println("Capturado:", r) } }() mayPanic() fmt.Println("Después de mayPanic") } ``` ### Mejor Práctica: Recuperación en el Borde ```go func server() { defer func() { if r := recover(); r != nil { log.Printf("Server panic: %v", r) os.Exit(1) } }() // Lógica del servidor... } ``` ## Registrar Errores ### Paquete log ```go import "log" if err != nil { log.Printf("operación fallida: %v", err) } if err != nil { log.Fatalf("error crítico: %v", err) } log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) ``` ### Logger Personalizado ```go logger := log.New(os.Stderr, "APP: ", log.Ldate|log.Ltime) logger.Printf("Iniciando servidor en puerto %d", 8080) logger.Fatalf("Falló al iniciar: %v", err) ``` ## Visibilidad de Errores ### Evitar Errores Ocultos ```go // MALO: ignora error bytes, _ := json.Marshal(data) // BUENO: manejar error bytes, err := json.Marshal(data) if err != nil { return fmt.Errorf("marshaling data: %w", err) } ``` ### Sin Supresión de Errores ```go // MALO: silenciosamente ignora errores if x > 0 { fmt.Println("positivo") } else if x < 0 { fmt.Println("negativo") } // ¡caso else ignorado! // BUENO if x > 0 { fmt.Println("positivo") } else if x < 0 { fmt.Println("negativo") } else { fmt.Println("cero") } ``` ## Resumen - Go usa manejo de errores explícito mediante valores de retorno - La interface `error` tiene un método: `Error() string` - Crear errores con `errors.New()` o `fmt.Errorf()` - Usar verbo `%w` para envolver errores - `errors.Is()` y `errors.As()` para inspección de errores - panic/recover reservado para situaciones verdaderamente excepcionales - Registrar o manejar cada error explícitamente - Nunca suprimir errores silenciosamente

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →