错误包装

在 Go 语言中,错误包装(Error Wrapping)是从 Go 1.13 开始引入的重要特性。它允许你为错误添加上下文信息,同时保留原始错误,形成错误链。以下是错误包装的全面指南:

1. 基础包装方法

使用 fmt.Errorf + %w 动词

func readConfig() error {
    _, err := os.Open("config.json")
    if err != nil {
        return fmt.Errorf("配置文件读取失败: %w", err)
    }
    return nil
}

func main() {
    err := readConfig()
    if err != nil {
        fmt.Println(err) // 输出: 配置文件读取失败: open config.json: no such file or directory
    }
}

2. 多层错误包装

func initSystem() error {
    if err := readConfig(); err != nil {
        return fmt.Errorf("系统初始化失败: %w", err)
    }
    return nil
}

func main() {
    if err := initSystem(); err != nil {
        fmt.Println(err) 
        // 输出: 系统初始化失败: 配置文件读取失败: open config.json: no such file or directory
    }
}

3. 自定义错误类型包装

4. 包装多个错误

Go 1.20+ 开始支持:

5. 处理被包装的错误

(1) 使用 errors.Is 检查特定错误

(2) 使用 errors.As 提取特定错误类型

(3) 获取完整错误链

6. 高级包装模式

添加堆栈跟踪 (使用第三方库)

条件性包装

7. 错误包装最佳实践

​场景​

​推荐做法​

​示例​

添加上下文信息

fmt.Errorf("上下文: %w", err)

fmt.Errorf("连接数据库失败: %w", err)

包装第三方错误

仅包装已知需要处理的错误

对于io.EOF可能不需要包装

创建新错误

使用errors.New

errors.New("无效输入")

需要携带额外数据

自定义错误类型实现Unwrap()

包含错误码、时间戳等

多重包装

Go 1.20+ 使用errors.Join

合并多个同级错误

错误传递

每层添加有意义的上下文

DB层服务层API层

8. 重要注意事项

  1. ​不要过度包装​

  2. ​保持错误信息简洁有用​

  3. ​处理被包装错误的能力​

完整包装流程图

通过合理使用错误包装,可以:

  1. 保留原始错误信息

  2. 添加上下文信息

  3. 创建清晰的错误处理路径

  4. 支持精确的错误检测

  5. 构建可维护的错误处理体系

始终考虑错误处理是业务逻辑的一部分,错误包装应使调试和维护更容易,而不是更复杂。

最后更新于