外观
练习 — error handling
对应知识点:
error·defer·panic·recover对应文档:docs/phase-02-core/error-handling.md代码目录:workspace/phase-02/error/
前置条件:掌握 function 多返回值、package 基础。
Level 1 — 基础
练习 1.1 · 返回 error
在 workspace/phase-02/error/main.go 编写:
要求:
- 函数
Divide(a, b float64) (float64, error) - b 为 0 时返回
errors.New("division by zero") - main 使用
if err != nil { log.Fatal(err) }处理
练习 1.2 · 错误包装
要求:
- 函数
LoadConfig(path string) ([]byte, error)内部调用os.ReadFile - 失败时用
fmt.Errorf("load config %s: %w", path, err)包装 - main 用
errors.Unwrap或%w链打印原始错误
练习 1.3 · defer 基础
要求:
- 函数
ProcessAGV(id string)开头defer fmt.Println("cleanup", id) - 函数中间
return或panic前打印 "processing" - 观察 defer 执行顺序(LIFO)
Level 2 — 应用
练习 2.1 · ParseSpeed
要求:
ParseSpeed(s string) (float64, error)- 空字符串、非数字、
"-1"(负数)均返回明确 error - 合法值如
"1.5"返回 float64 - table-driven 思路:main 中测试至少 4 种输入
练习 2.2 · defer 关闭资源
要求:
ReadTelemetryFile(path string) (string, error)使用os.Opendefer f.Close()确保文件关闭- 读取失败时仍正确 Close(理解 defer 与 return 配合)
练习 2.3 · panic 与 recover
要求:
- 函数
SafeRun(fn func())使用 defer + recover 捕获 panic - 捕获后打印
"recovered:"+ panic 值,程序不崩溃 - 演示:传入会 panic 的函数(如数组越界)与正常函数
Level 3 — 综合
练习 3.1 · 错误链
要求:
- 三层调用:
fetchRaw() → parse() → validate() - 每层失败用
%w包装,最终 main 打印完整错误链 - 场景:解析 AGV 遥测 JSON 字符串
练习 3.2 · error vs panic 决策
在代码注释中说明以下场景应返回 error 还是 panic(至少各 2 例):
- JSON 格式错误
- 数据库连接池初始化失败(生产环境)
- 用户传入非法 deviceId 格式
- 程序 invariant 被违反(如内部 map 为 nil)
并实现其中 2 个返回 error、1 个使用 panic+recover 的示例。
Level 4 — 项目实践
练习 4.1 · AGV 遥测解析链
在 workspace/phase-02/error/ 实现完整链路:
文件:
telemetry.go:Parse(raw string) (Telemetry, error)、Validate(t Telemetry) error、Save(t Telemetry) errormain.go:模拟 3 条输入(合法、格式错、校验失败)
要求:
Telemetry含 DeviceID、X、Y、Battery- 任一步失败,defer 记录
"failed at step: ..."日志 - 不向调用方 panic(除 main 顶层可选 recover)
- 错误信息包含 deviceId 上下文
学习检查
- [ ] Go 中 error 是返回值还是异常?
- [ ]
%w与%v在 fmt.Errorf 中的区别? - [ ] defer 的执行时机与顺序?
- [ ] 何时该用 panic,何时必须返回 error?
提交方式
检查答案 — error handling 练习 X.X