Menu
CoddyTech

复习:安全除法

本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 44 课,共 68 课。

challenge icon

挑战

简单

构建一个功能全面的数学计算器,实现安全除法,并支持多种自定义错误类型和完善的错误处理。本挑战结合了自定义错误类型、错误包装和错误检查,打造一个能够妥善处理各种数学运算失败情况的可靠系统。

你将收到两个输入:

  • 一个包含运算详情的字符串,格式为 "operation,num1,num2,precision"(例如:"divide,10,0,2")
  • 一个包含计算器设置的字符串,格式为 "calculator_name,mode"(例如:"ScientificCalc,strict")

你的任务是:

  1. 创建两种自定义错误类型:
    • 创建一个 DivisionError 结构体,包含字段 Dividend(float64)和 Divisor(float64)
    • 创建一个 ValidationError 结构体,包含字段 Field(string)和 Value(float64)
  2. 为 DivisionError 实现 Error() string 方法,使其返回:"division error: cannot divide [dividend] by [divisor]"
  3. 为 ValidationError 实现 Error() string 方法,使其返回:"validation error: invalid [field] value [value]"
  4. 按逗号拆分第一个输入,获取 operation、num1、num2 和 precision
  5. 按逗号拆分第二个输入,获取计算器名称和 mode
  6. 将数字字符串转换为 float64,并将精度转换为 int
  7. 创建一个 safeDivide 函数,接收两个 float64 参数并返回 (float64, error):
    • 如果 divisor 为 0,则返回 0 和一个包含被除数与除数值的 DivisionError
    • 如果 dividend 为负数且 mode 为 "strict",则返回 0 和一个字段为 "dividend"、值为被除数的 ValidationError
    • 如果 divisor 为负数且 mode 为 "strict",则返回 0 和一个字段为 "divisor"、值为除数的 ValidationError
    • 否则,返回除法结果和 nil
  8. 创建一个 performCalculation 函数,用于包装 safeDivide 的结果:
    • 如果 safeDivide 返回错误,则用以下内容包装错误:"calculation failed in [calculator_name]: %w"
    • 如果成功,则返回结果和 nil
  9. 调用 performCalculation 并处理结果:
    • 如果没有错误:打印 "Calculation successful: [result_formatted_to_precision_decimal_places]"
    • 如果存在错误:打印 "Calculation failed: [error_message]"
  10. 使用 errors.As 检查包装后的错误是否属于特定错误类型:
    • 打印 "Checking for division error: [true/false]"
    • 打印 "Checking for validation error: [true/false]"
  11. 如果找到 DivisionError,则打印其详情:
    • "Division Error Details:"
    • "Dividend: [dividend]"
    • "Divisor: [divisor]"
  12. 如果找到 ValidationError,则打印其详情:
    • "Validation Error Details:"
    • "Field: [field]"
    • "Value: [value]"
  13. 显示最终摘要:
    • "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 在线编译器