Итоги: Безопасное деление
Часть раздела Логика и управление потоком путешествия по GO на Coddy — урок 44 из 68.
Задание
ЛегкоСоздайте комплексный математический калькулятор, который реализует безопасное деление с использованием нескольких пользовательских типов ошибок и правильной обработкой ошибок. Эта задача объединяет пользовательские типы ошибок, оборачивание ошибок (error wrapping) и проверку ошибок для создания надежной системы, которая корректно обрабатывает различные сбои математических операций.
Вы получите два входных значения:
- Строка, содержащая детали операции в формате
"operation,num1,num2,precision"(например,"divide,10,0,2") - Строка, содержащая настройки калькулятора в формате
"calculator_name,mode"(например,"ScientificCalc,strict")
Ваша задача:
- Создать два пользовательских типа ошибок:
- Структура
DivisionErrorс полямиDividend(float64) иDivisor(float64) - Структура
ValidationErrorс полямиField(string) иValue(float64)
- Структура
- Реализовать метод
Error() stringдляDivisionError, который возвращает:"division error: cannot divide [dividend] by [divisor]" - Реализовать метод
Error() stringдляValidationError, который возвращает:"validation error: invalid [field] value [value]" - Разобрать первый входной параметр, разделив его по запятым, чтобы получить operation, num1, num2 и precision
- Разобрать второй входной параметр, разделив его по запятым, чтобы получить calculator name и mode
- Преобразовать строковые числа в float64, а precision — в int
- Создать функцию
safeDivide, которая принимает два параметра float64 и возвращает (float64, error):- Если делитель равен 0, вернуть 0 и
DivisionErrorсо значениями dividend и divisor - Если делимое отрицательное и mode равен
"strict", вернуть 0 иValidationErrorс полем"dividend"и значением dividend - Если делитель отрицательный и mode равен
"strict", вернуть 0 иValidationErrorс полем"divisor"и значением divisor - В противном случае вернуть результат деления и nil
- Если делитель равен 0, вернуть 0 и
- Создать функцию
performCalculation, которая оборачивает результатsafeDivide:- Если
safeDivideвозвращает ошибку, обернуть ее строкой:"calculation failed in [calculator_name]: %w" - В случае успеха вернуть результат и nil
- Если
- Вызвать
performCalculationи обработать результат:- Если ошибки нет: вывести
"Calculation successful: [result_formatted_to_precision_decimal_places]" - Если ошибка есть: вывести
"Calculation failed: [error_message]"
- Если ошибки нет: вывести
- Использовать
errors.Asдля проверки конкретных типов ошибок в обернутой ошибке:- Вывести
"Checking for division error: [true/false]" - Вывести
"Checking for validation error: [true/false]"
- Вывести
- Если обнаружена ошибка
DivisionError, вывести ее детали:"Division Error Details:""Dividend: [dividend]""Divisor: [divisor]"
- Если обнаружена ошибка
ValidationError, вывести ее детали:"Validation Error Details:""Field: [field]""Value: [value]"
- Отобразить итоговую сводку:
"Calculator Summary:""Name: [calculator_name]""Mode: [mode]""Operation: [operation]""Input: [num1] [operation_symbol] [num2]", где operation_symbol — это "/" для деления"Precision: [precision] decimal places""Status: [Success/Failed]"
Используйте пакет strings для разделения входных строк по запятым, пакет strconv для преобразования строк в числа, пакет errors для errors.As и пакет fmt для оборачивания и форматирования ошибок. Эта задача демонстрирует, как пользовательские типы ошибок, оборачивание ошибок и правильная проверка ошибок работают вместе для создания надежных систем обработки ошибок, предоставляющих подробную информацию о различных типах сбоев.
Попробуйте сами
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Чтение входных данных
var operationInput string
var settingsInput string
fmt.Scanln(&operationInput)
fmt.Scanln(&settingsInput)
// Разбор входных данных операции (operation,num1,num2,precision)
operationParts := strings.Split(operationInput, ",")
operation := operationParts[0]
num1, _ := strconv.ParseFloat(operationParts[1], 64)
num2, _ := strconv.ParseFloat(operationParts[2], 64)
precision, _ := strconv.Atoi(operationParts[3])
// Разбор входных данных настроек (calculator_name,mode)
settingsParts := strings.Split(settingsInput, ",")
calculatorName := settingsParts[0]
mode := settingsParts[1]
// TODO: Напишите ваш код ниже
// 1. Создайте структуры DivisionError и ValidationError с методами Error()
// 2. Реализуйте функцию safeDivide
// 3. Реализуйте функцию performCalculation
// 4. Вызовите performCalculation и обработайте результаты
// 5. Используйте errors.As для проверки конкретных типов ошибок
// 6. Выведите детали ошибки, если она обнаружена
// 7. Отобразите итоговую сводку
}Все уроки раздела Логика и управление потоком
1Продвинутое управление потоком выполнения
Switch с использованием `fallthrough`Выход из вложенных цикловПродолжение конкретного циклаОператор `goto`Итоги: Продвинутое управление циклами4Проект: Простой список задач
Настройка проектаДобавление задачи7Углубленная обработка ошибок
Пользовательские типы ошибокОбертывание ошибок с помощью `%w`Распаковка с помощью `errors.Is`Распаковка с помощью `errors.As`Понимание `panic`Использование `recover`Итоги: Безопасное деление2Структуры и методы
Определение методов для структурПолучатели по значениюПолучатели по указателюВыбор типа получателяМетоды против функцийИтоги: поведение структур5Карты: подробный разбор
Карты структурУказатели как значения картПроверка карт на nilСравнение картИтоги: счетчик частоты слов3Интерфейсы (Основы)
Что такое интерфейс?Определение интерфейсаРеализация интерфейсаИспользование интерфейсных типовПустой интерфейсУтверждение типаПереключатель типовИтоги: Фигуры и поведение