用途
本技能用于在 Go 应用中正确地处理错误,帮助开发者掌握 Go 的错误处理模式,包括错误包装、哨兵错误、自定义错误类型以及 errors 包的使用,从而构建健壮的应用。
主要能力
基础错误处理
使用 errors.New 创建错误,或使用 fmt.Errorf 返回带说明的错误。示例中 divide 函数在除数为 0 时返回 errors.New("division by zero"),processFile 在文件名为空时返回 fmt.Errorf("filename cannot be empty")。
错误包装(Go 1.13+)
使用 fmt.Errorf 配合 %w 动词为错误添加上下文,例如 fmt.Errorf("failed to read config: %w", err)。使用 errors.Unwrap 解包一层,使用 errors.Is 判断错误链中是否包含特定错误(如 os.ErrNotExist)。
哨兵错误
通过包级变量定义可比较的错误值,例如 ErrNotFound、ErrUnauthorized、ErrInvalidInput,并在调用处用 errors.Is 进行判断。
自定义错误类型
实现 error 接口(Error() string 方法),例如 ValidationError 结构体携带 Field 与 Message 字段。使用 errors.As 进行类型断言,提取具体的错误类型信息。
多错误处理
定义 MultiError 结构体收集多个错误,提供 Error() 与 Add() 方法,用于一次性校验多个字段并返回全部错误。
panic 与 recover
panic 用于不可恢复的错误(如 mustConnect 连接数据库失败);recover 用于从 panic 中恢复,例如 safeExecute 通过 defer 捕获 panic 并转换为 error 返回。
错误处理模式
提前返回模式:每一步操作后立即检查错误并返回,使用 %w 逐层包装。错误变量命名建议使用具体名称(如 errDB、errCache),避免到处复用 err 增加调试难度。
pkg/errors 旧式用法
使用 github.com/pkg/errors 的 errors.Wrap 包装错误,并通过 %+v 打印堆栈信息。
错误日志
使用 log/slog 进行结构化错误日志记录,按级别(Error、Warn)记录并附带 orderID、error 等字段。
HTTP 错误处理
定义 APIError 类型(含 Code 与 Message),在 writeError 中通过 errors.As 判断并写出对应状态码与 JSON 响应,否则返回 500 与通用错误信息。
错误上下文
定义 ContextError 结构体(Op、Path、Err),实现 Error() 与 Unwrap() 方法,为错误附加操作与路径信息。
错误测试
使用 testing 包测试错误条件,包括判断错误非空、比较错误消息、用 errors.Is 验证包装错误、用 errors.As 验证自定义错误类型及其字段。
使用方式
本技能以代码示例形式给出各类错误处理写法,开发者可按需参考对应片段:基础错误创建、%w 包装、errors.Is/As 判断、自定义错误类型实现、MultiError 收集、panic/recover、slog 日志、HTTP 错误响应、错误测试等。
适用场景
- 在 Go 应用中正确处理错误
- 为错误添加上下文而不丢失信息
- 定义领域特定的错误类型
- 检查特定错误条件
- 包装错误并附加额外上下文
- 以适当细节记录错误日志
- 从 HTTP 处理器返回错误
- 全面测试错误条件
- 构建错误弹性系统
- 基于错误类型实现重试逻辑
最佳实践
- 始终检查错误,绝不忽略
- 返回错误而不是记录后继续执行
- 使用 fmt.Errorf 配合 %w 包装错误
- 使用 errors.Is 比较哨兵错误
- 使用 errors.As 进行类型断言
- 在错误消息中提供上下文
- 为领域错误使用自定义错误类型
- 库中不要 panic,应返回错误
- 在适当级别记录错误
- 像测试正常路径一样彻底测试错误路径
常见陷阱
- 用 _ 赋值忽略错误
- 不包装错误(丢失上下文)
- 使用 == 比较错误
- 用 panic 代替返回错误
- 未处理所有错误情况
- 创建过多自定义错误类型
- 错误消息格式不佳
- 未测试错误条件
- 在 goroutine 中吞掉错误
- 错误中未提供足够上下文
限制
资料未提供该技能的安装方式、运行环境要求、版本兼容范围或收费信息,暂未提供。