复习:安全除法
本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 44 课,共 68 课。
挑战
简单构建一个功能全面的数学计算器,实现安全除法,并支持多种自定义错误类型和完善的错误处理。本挑战结合了自定义错误类型、错误包装和错误检查,打造一个能够妥善处理各种数学运算失败情况的可靠系统。
你将收到两个输入:
- 一个包含运算详情的字符串,格式为
"operation,num1,num2,precision"(例如:"divide,10,0,2") - 一个包含计算器设置的字符串,格式为
"calculator_name,mode"(例如:"ScientificCalc,strict")
你的任务是:
- 创建两种自定义错误类型:
- 创建一个
DivisionError结构体,包含字段Dividend(float64)和Divisor(float64) - 创建一个
ValidationError结构体,包含字段Field(string)和Value(float64)
- 创建一个
- 为
DivisionError实现Error() string方法,使其返回:"division error: cannot divide [dividend] by [divisor]" - 为
ValidationError实现Error() string方法,使其返回:"validation error: invalid [field] value [value]" - 按逗号拆分第一个输入,获取 operation、num1、num2 和 precision
- 按逗号拆分第二个输入,获取计算器名称和 mode
- 将数字字符串转换为 float64,并将精度转换为 int
- 创建一个
safeDivide函数,接收两个 float64 参数并返回 (float64, error):- 如果 divisor 为 0,则返回 0 和一个包含被除数与除数值的
DivisionError - 如果 dividend 为负数且 mode 为
"strict",则返回 0 和一个字段为"dividend"、值为被除数的ValidationError - 如果 divisor 为负数且 mode 为
"strict",则返回 0 和一个字段为"divisor"、值为除数的ValidationError - 否则,返回除法结果和 nil
- 如果 divisor 为 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. 创建包含 Error() 方法的 DivisionError 和 ValidationError 结构体
// 2. 实现 safeDivide 函数
// 3. 实现 performCalculation 函数
// 4. 调用 performCalculation 并处理结果
// 5. 使用 errors.As 检查特定的错误类型
// 6. 如果发现错误,打印错误详情
// 7. 显示最终汇总
}逻辑与流程中的所有课
自己练习: Go 在线编译器