Repaso - División segura
Parte de la sección Lógica y Flujo del Journey de GO de Coddy — lección 44 de 68.
Desafío
FácilConstruye una calculadora matemática integral que implemente una división segura con múltiples tipos de errores personalizados y un manejo de errores adecuado. Este desafío combina tipos de errores personalizados, envoltura de errores (error wrapping) y comprobación de errores para crear un sistema robusto que maneje con elegancia varios fallos en las operaciones matemáticas.
Recibirás dos entradas:
- Una cadena que contiene los detalles de la operación en el formato
"operation,num1,num2,precision"(por ejemplo,"divide,10,0,2") - Una cadena que contiene la configuración de la calculadora en el formato
"calculator_name,mode"(por ejemplo,"ScientificCalc,strict")
Tu tarea es:
- Crear dos tipos de errores personalizados:
- Estructura
DivisionErrorcon los camposDividend(float64) yDivisor(float64) - Estructura
ValidationErrorcon los camposField(string) yValue(float64)
- Estructura
- Implementar el método
Error() stringparaDivisionErrorque devuelva:"division error: cannot divide [dividend] by [divisor]" - Implementar el método
Error() stringparaValidationErrorque devuelva:"validation error: invalid [field] value [value]" - Analizar la primera entrada dividiéndola por comas para obtener operation, num1, num2 y precision
- Analizar la segunda entrada dividiéndola por comas para obtener calculator name y mode
- Convertir los números de cadena a float64 y precision a int
- Crear una función
safeDivideque tome dos parámetros float64 y devuelva (float64, error):- Si divisor es 0, devolver 0 y un
DivisionErrorcon los valores de dividend y divisor - Si dividend es negativo y mode es
"strict", devolver 0 y unValidationErrorcon el campo"dividend"y el valor de dividend - Si divisor es negativo y mode es
"strict", devolver 0 y unValidationErrorcon el campo"divisor"y el valor de divisor - De lo contrario, devolver el resultado de la división y nil
- Si divisor es 0, devolver 0 y un
- Crear una función
performCalculationque envuelva el resultado desafeDivide:- Si
safeDividedevuelve un error, envolverlo con:"calculation failed in [calculator_name]: %w" - Si tiene éxito, devolver el resultado y nil
- Si
- Llamar a
performCalculationy manejar el resultado:- Si no hay error: imprimir
"Calculation successful: [result_formatted_to_precision_decimal_places]" - Si existe un error: imprimir
"Calculation failed: [error_message]"
- Si no hay error: imprimir
- Usar
errors.Aspara buscar tipos de errores específicos en el error envuelto:- Imprimir
"Checking for division error: [true/false]" - Imprimir
"Checking for validation error: [true/false]"
- Imprimir
- Si se encuentra un
DivisionError, imprimir sus detalles:"Division Error Details:""Dividend: [dividend]""Divisor: [divisor]"
- Si se encuentra un
ValidationError, imprimir sus detalles:"Validation Error Details:""Field: [field]""Value: [value]"
- Mostrar un resumen final:
"Calculator Summary:""Name: [calculator_name]""Mode: [mode]""Operation: [operation]""Input: [num1] [operation_symbol] [num2]"donde operation_symbol es "/" para divide"Precision: [precision] decimal places""Status: [Success/Failed]"
Utiliza el paquete strings para dividir las cadenas de entrada por comas, el paquete strconv para convertir cadenas a números, el paquete errors para errors.As, y el paquete fmt para la envoltura y el formateo de errores. Este desafío demuestra cómo los tipos de errores personalizados, la envoltura de errores y la comprobación adecuada de errores trabajan juntos para crear sistemas robustos de manejo de errores que proporcionan información detallada sobre diferentes tipos de fallos.
Pruébalo tú mismo
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Leer entrada
var operationInput string
var settingsInput string
fmt.Scanln(&operationInput)
fmt.Scanln(&settingsInput)
// Analizar entrada de operación (operación,num1,num2,precisión)
operationParts := strings.Split(operationInput, ",")
operation := operationParts[0]
num1, _ := strconv.ParseFloat(operationParts[1], 64)
num2, _ := strconv.ParseFloat(operationParts[2], 64)
precision, _ := strconv.Atoi(operationParts[3])
// Analizar entrada de configuración (nombre_calculadora,modo)
settingsParts := strings.Split(settingsInput, ",")
calculatorName := settingsParts[0]
mode := settingsParts[1]
// TODO: Escribe tu código a continuación
// 1. Crear las estructuras DivisionError y ValidationError con métodos Error()
// 2. Implementar la función safeDivide
// 3. Implementar la función performCalculation
// 4. Llamar a performCalculation y manejar los resultados
// 5. Usar errors.As para verificar tipos de error específicos
// 6. Imprimir detalles del error si se encuentran
// 7. Mostrar el resumen final
}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