Desenvolver con `errors.Is`
Parte de la sección Lógica y Flujo del Journey de GO de Coddy — lección 40 de 68.
Al trabajar con errores envueltos, necesitas una forma de comprobar si un error específico existe en cualquier lugar de la cadena de errores. La función errors.Is proporciona exactamente esta capacidad, permitiéndote identificar errores centinela incluso cuando han sido envueltos varias veces.
La función errors.Is toma dos parámetros: el error que deseas examinar y el error de destino que estás buscando. Devuelve true si el error de destino se encuentra en cualquier lugar de la cadena de errores:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}Esta es la forma moderna y recomendada de comprobar errores específicos en Go. A diferencia de la comparación de cadenas o las comprobaciones de igualdad directa, errors.Is funciona correctamente con errores envueltos y sigue la cadena de errores para encontrar coincidencias. Esto hace que el manejo de errores sea robusto y confiable, incluso cuando los errores pasan a través de múltiples capas de su aplicación.
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Desafío
FácilConstruye un sistema de monitoreo de conexión a base de datos que utilice errors.Is para identificar errores de conexión específicos en cadenas de errores envueltos (wrapped errors). Este desafío demuestra cómo usar errors.Is para detectar errores centinela incluso cuando han sido envueltos con contexto adicional a través de múltiples capas de la aplicación.
Recibirás dos entradas:
- Una cadena que contiene detalles de la operación de la base de datos en el formato
"database_name,operation,error_type"(por ejemplo,"users_db,connect,connection_timeout") - Una cadena que contiene el contexto de la aplicación en el formato
"service_name,retry_count"(por ejemplo,"AuthService,3")
Tu tarea es:
- Definir tres errores centinela usando
errors.New():ErrConnectionTimeoutcon el mensaje"connection timeout"ErrConnectionRefusedcon el mensaje"connection refused"ErrDatabaseNotFoundcon el mensaje"database not found"
- Analizar la primera entrada dividiéndola por comas para obtener el nombre de la base de datos, la operación y el tipo de error
- Analizar la segunda entrada dividiéndola por comas para obtener el nombre del servicio y el número de reintentos
- Crear el error original basado en el tipo de error:
- Si el tipo de error es
"connection_timeout": usaErrConnectionTimeout - Si el tipo de error es
"connection_refused": usaErrConnectionRefused - Si el tipo de error es
"database_not_found": usaErrDatabaseNotFound - Para cualquier otro tipo de error: usa
errors.New("unknown database error")
- Si el tipo de error es
- Crear un error envuelto a nivel de base de datos usando
fmt.Errorfcon%w:"failed to [operation] database [database_name]: %w" - Crear un error envuelto a nivel de servicio:
"[service_name] database operation failed after [retry_count] retries: %w" - Usar
errors.Ispara verificar si el error envuelto final coincide con cada error centinela y mostrar los resultados:"Checking for connection timeout: [true/false]""Checking for connection refused: [true/false]""Checking for database not found: [true/false]"
- Mostrar la cadena de errores:
"Error Chain:""Original: [original_error_message]""Database level: [database_level_error_message]""Service level: [service_level_error_message]"
- Mostrar el análisis del error:
"Error Analysis:""Database: [database_name]""Operation: [operation]""Service: [service_name]""Retries: [retry_count]""Error type detected: [detected_error_type]"donde detected_error_type es uno de "Connection Timeout", "Connection Refused", "Database Not Found", o "Unknown Error"
Usa el paquete strings para dividir las cadenas de entrada por comas, el paquete errors para los errores centinela y errors.Is, y el paquete fmt para envolver los errores. Este desafío demuestra cómo errors.Is proporciona una identificación de errores robusta que funciona correctamente con errores envueltos, lo que lo hace esencial para un manejo de errores confiable en aplicaciones complejas.
Hoja de referencia
La función errors.Is comprueba si un error específico existe en cualquier lugar de una cadena de errores, incluso cuando está envuelto varias veces:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}errors.Is toma dos parámetros: el error a examinar y el error de destino a buscar. Devuelve true si el error de destino se encuentra en cualquier lugar de la cadena de errores.
Esta es la forma moderna y recomendada de comprobar errores específicos en Go, ya que funciona correctamente con errores envueltos, a diferencia de la comparación de cadenas o las comprobaciones de igualdad directa.
Pruébalo tú mismo
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// Leer entrada
var dbOperation string
var appContext string
fmt.Scanln(&dbOperation)
fmt.Scanln(&appContext)
// Analizar entradas
dbParts := strings.Split(dbOperation, ",")
databaseName := dbParts[0]
operation := dbParts[1]
errorType := dbParts[2]
contextParts := strings.Split(appContext, ",")
serviceName := contextParts[0]
retryCount := contextParts[1]
// TODO: Escribe tu código a continuación
// 1. Definir los tres errores centinela usando errors.New()
// 2. Crear el error original basado en el tipo de error
// 3. Crear un error envuelto a nivel de base de datos usando fmt.Errorf con %w
// 4. Crear un error envuelto a nivel de servicio
// 5. Usar errors.Is para verificar cada error centinela
// 6. Mostrar los resultados y la cadena de errores
}Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Lógica y Flujo
1Flujo de control avanzado
Switch con `fallthrough`Salir de bucles anidadosContinuar un bucle específicoLa sentencia `goto`Repaso: Control de bucles avanzado4Proyecto: Lista de tareas sencilla
Configuración del proyectoAñadir una tarea7Manejo de errores a fondo
Tipos de error personalizadosEnvolver errores con `%w`Desenvolver con `errors.Is`Desenvolver con `errors.As`Entendiendo `panic`Uso de `recover`Repaso - División segura2Estructuras y Métodos
Definición de métodos en estructurasReceptores de valorReceptores de punteroElegir receptoresMétodos vs FuncionesResumen - Comportamiento de estructuras5Mapas en profundidad
Mapas de StructsPunteros como valores de MapVerificación de Maps NilComparación de MapsResumen - Contador de frecuencia de palabras3Interfaces (Conceptos básicos)
¿Qué es una interfaz?Definir una interfazImplementar una interfazUso de tipos de interfazInterfaz vacíaAserciones de tipoType SwitchResumen: Formas y comportamientos