diff --git a/02_core_concepts/04_error_handling/main.go b/02_core_concepts/04_error_handling/main.go index 0db886e..3cd8849 100644 --- a/02_core_concepts/04_error_handling/main.go +++ b/02_core_concepts/04_error_handling/main.go @@ -1,5 +1,107 @@ package main -func main() { - // TODO +import ( + "errors" // 提供基本错误处理功能 + "fmt" // 用于格式化输出 + "os" // 提供操作系统功能 + "strconv" // 用于字符串转换 +) + +// DivisionError 是一个自定义错误类型 +// 它包含除法运算的被除数、除数和错误信息 +type DivisionError struct { + dividend float64 // 被除数 + divisor float64 // 除数 + message string // 错误信息 +} + +// Error 方法实现了 error 接口 +// 这使得 DivisionError 可以作为一个错误类型使用 +func (e *DivisionError) Error() string { + return fmt.Sprintf("%s: %f / %f", e.message, e.dividend, e.divisor) +} + +// divide 函数执行除法运算,并处理除数为零的情况 +// 参数: +// - dividend: 被除数 +// - divisor: 除数 +// +// 返回: +// - float64: 除法结果 +// - error: 可能的错误 +func divide(dividend, divisor float64) (float64, error) { + if divisor == 0 { + // 当除数为零时,返回自定义错误 + return 0, &DivisionError{ + dividend: dividend, + divisor: divisor, + message: "cannot divide by zero", + } + } + return dividend / divisor, nil +} + +// readConfig 函数读取配置文件并演示错误包装 +// 使用 fmt.Errorf 和 %w 来包装底层错误 +func readConfig(filename string) (string, error) { + data, err := os.ReadFile(filename) + if err != nil { + // 使用 %w 包装原始错误,保留错误链 + return "", fmt.Errorf("failed to read config file: %w", err) + } + return string(data), nil +} + +// parseAge 函数解析年龄字符串,展示多重错误处理 +// 包含多个验证步骤,每步都可能产生不同的错误 +func parseAge(age string) (int, error) { + // 检查空字符串 + if age == "" { + return 0, errors.New("age cannot be empty") + } + + // 将字符串转换为整数 + n, err := strconv.Atoi(age) + if err != nil { + // 包装转换错误 + return 0, fmt.Errorf("invalid age format: %w", err) + } + + // 验证年龄范围 + if n < 0 || n > 150 { + return 0, fmt.Errorf("age %d is out of valid range (0-150)", n) + } + + return n, nil +} + +func main() { + // 示例1:演示自定义错误的使用 + result, err := divide(10, 0) + if err != nil { + fmt.Printf("Division error: %v\n", err) + } else { + fmt.Printf("Result: %f\n", result) + } + + // 示例2:演示错误包装和错误类型断言 + _, err = readConfig("nonexistent.txt") + if err != nil { + fmt.Printf("Config error: %v\n", err) + // 使用 os.IsNotExist 判断具体的错误类型 + if os.IsNotExist(err) { + fmt.Println("The file does not exist") + } + } + + // 示例3:演示多重错误处理 + ages := []string{"25", "-5", "abc", "200", ""} + for _, age := range ages { + parsedAge, err := parseAge(age) + if err != nil { + fmt.Printf("Error parsing age '%s': %v\n", age, err) + continue + } + fmt.Printf("Valid age: %d\n", parsedAge) + } }