Recapitulação - Divisão Segura
Parte da seção Lógica & Fluxo do Journey de GO da Coddy — lição 44 de 68.
Desafio
FácilConstrua uma calculadora matemática abrangente que implemente a divisão segura com múltiplos tipos de erro personalizados e tratamento de erros adequado. Este desafio combina tipos de erro personalizados, empacotamento de erros (error wrapping) e verificação de erros para criar um sistema robusto que lida com várias falhas de operações matemáticas de forma elegante.
Você receberá duas entradas:
- Uma string contendo detalhes da operação no formato
"operation,num1,num2,precision"(ex:"divide,10,0,2") - Uma string contendo as configurações da calculadora no formato
"calculator_name,mode"(ex:"ScientificCalc,strict")
Sua tarefa é:
- Criar dois tipos de erro personalizados:
- Struct
DivisionErrorcom os camposDividend(float64) eDivisor(float64) - Struct
ValidationErrorcom os camposField(string) eValue(float64)
- Struct
- Implementar o método
Error() stringparaDivisionErrorque retorna:"division error: cannot divide [dividend] by [divisor]" - Implementar o método
Error() stringparaValidationErrorque retorna:"validation error: invalid [field] value [value]" - Analisar a primeira entrada dividindo-a por vírgulas para obter operation, num1, num2 e precision
- Analisar a segunda entrada dividindo-a por vírgulas para obter calculator name e mode
- Converter os números em string para float64 e precision para int
- Criar uma função
safeDivideque recebe dois parâmetros float64 e retorna (float64, error):- Se o divisor for 0, retorne 0 e um
DivisionErrorcom os valores de dividendo e divisor - Se o dividendo for negativo e o modo for
"strict", retorne 0 e umValidationErrorcom o campo"dividend"e o valor do dividendo - Se o divisor for negativo e o modo for
"strict", retorne 0 e umValidationErrorcom o campo"divisor"e o valor do divisor - Caso contrário, retorne o resultado da divisão e nil
- Se o divisor for 0, retorne 0 e um
- Criar uma função
performCalculationque empacota o resultado desafeDivide:- Se
safeDivideretornar um erro, empacote-o com:"calculation failed in [calculator_name]: %w" - Se for bem-sucedido, retorne o resultado e nil
- Se
- Chamar
performCalculatione tratar o resultado:- Se não houver erro: imprima
"Calculation successful: [result_formatted_to_precision_decimal_places]" - Se houver erro: imprima
"Calculation failed: [error_message]"
- Se não houver erro: imprima
- Usar
errors.Aspara verificar tipos de erro específicos no erro empacotado:- Imprima
"Checking for division error: [true/false]" - Imprima
"Checking for validation error: [true/false]"
- Imprima
- Se um
DivisionErrorfor encontrado, imprima seus detalhes:"Division Error Details:""Dividend: [dividend]""Divisor: [divisor]"
- Se um
ValidationErrorfor encontrado, imprima seus detalhes:"Validation Error Details:""Field: [field]""Value: [value]"
- Exibir um resumo final:
"Calculator Summary:""Name: [calculator_name]""Mode: [mode]""Operation: [operation]""Input: [num1] [operation_symbol] [num2]"onde operation_symbol é "/" para divisão"Precision: [precision] decimal places""Status: [Success/Failed]"
Use o pacote strings para dividir as strings de entrada por vírgulas, o pacote strconv para converter strings em números, o pacote errors para errors.As e o pacote fmt para empacotamento e formatação de erros. Este desafio demonstra como tipos de erro personalizados, empacotamento de erros e a verificação adequada de erros trabalham juntos para criar sistemas robustos de tratamento de erros que fornecem informações detalhadas sobre diferentes tipos de falhas.
Experimente você mesmo
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Ler entrada
var operationInput string
var settingsInput string
fmt.Scanln(&operationInput)
fmt.Scanln(&settingsInput)
// Analisar entrada da operação (operação,num1,num2,precisão)
operationParts := strings.Split(operationInput, ",")
operation := operationParts[0]
num1, _ := strconv.ParseFloat(operationParts[1], 64)
num2, _ := strconv.ParseFloat(operationParts[2], 64)
precision, _ := strconv.Atoi(operationParts[3])
// Analisar entrada de configurações (nome_da_calculadora,modo)
settingsParts := strings.Split(settingsInput, ",")
calculatorName := settingsParts[0]
mode := settingsParts[1]
// TODO: Escreva seu código abaixo
// 1. Criar as structs DivisionError e ValidationError com métodos Error()
// 2. Implementar a função safeDivide
// 3. Implementar a função performCalculation
// 4. Chamar performCalculation e tratar os resultados
// 5. Usar errors.As para verificar tipos de erro específicos
// 6. Imprimir detalhes do erro se encontrado
// 7. Exibir resumo final
}Todas as lições de Lógica & Fluxo
1Fluxo de Controle Avançado
Switch com `fallthrough`Interrompendo Loops AninhadosContinuando um Loop EspecíficoA Instrução `goto`Recapitulação - Controle de Loop Avançado4Projeto: Lista de Tarefas Simples
Configuração do ProjetoAdicionando uma Tarefa7Tratamento de Erros em Profundidade
Tipos de Erro PersonalizadosWrapping de Erros com `%w`Unwrapping com `errors.Is`Unwrapping com `errors.As`Entendendo o `panic`Usando o `recover`Recapitulação - Divisão Segura2Structs e Métodos
Definindo Métodos em StructsRecebedores de ValorRecebedores de PonteiroEscolhendo RecebedoresMétodos vs FunçõesRecapitulação - Comportamento de Structs5Mapas em Profundidade
Mapas de StructsPonteiros como Valores de MapVerificando Mapas NilComparando MapasRecapitulação - Contador de Frequência de Palavras3Interfaces (O Básico)
O que é uma Interface?Definindo uma InterfaceImplementando uma InterfaceUsando Tipos de InterfaceInterface VaziaAsserções de TipoType SwitchRecapitulação - Formas e Comportamentos