0

0

如何在Golang中处理函数返回多错误_使用errors.Join或自定义结构

P粉602998670

P粉602998670

发布时间:2025-12-22 15:49:02

|

240人浏览过

|

来源于php中文网

原创

Go 1.20 的 errors.Join 适合简单聚合多个错误,支持嵌套、遍历及 errors.Is/As 判断;自定义错误结构适用于需携带上下文、分类或可恢复行为的场景;二者可组合使用。

如何在golang中处理函数返回多错误_使用errors.join或自定义结构

Go 1.20 引入了 errors.Join,为处理多个错误提供了标准、简洁的方式;而自定义错误结构则适合需要携带上下文、分类或可恢复行为的场景。二者不互斥,可根据实际需求选择或组合使用。

用 errors.Join 合并多个错误(推荐用于简单聚合)

errors.Join 将零个或多个错误合并为一个实现了 error 接口的值,支持嵌套、遍历和判断是否包含某类错误(配合 errors.Iserrors.As)。它轻量、无副作用,适合“尽力执行 + 收集失败”的场景,比如批量操作、资源清理等。

示例:关闭多个文件时收集所有关闭错误

func closeAll(files ...*os.File) error {
    var errs []error
    for _, f := range files {
        if err := f.Close(); err != nil {
            errs = append(errs, fmt.Errorf("closing %s: %w", f.Name(), err))
        }
    }
    return errors.Join(errs...)
}

调用后可统一检查:

立即学习go语言免费学习笔记(深入)”;

  • 是否完全成功:if err == nil
  • 是否含特定错误类型:errors.Is(err, os.ErrClosed)(只要任一子错误匹配即为 true)
  • 提取第一个匹配的底层错误:var pathErr *os.PathError; if errors.As(err, &pathErr) { ... }

自定义错误结构(适合需结构化信息或控制行为)

当多个错误需区分来源、优先级、是否可忽略,或需附带字段(如失败项索引、重试次数、HTTP 状态码)时,定义结构体更清晰。注意实现 Error() 方法,并可选择性实现 Unwrap() 以支持 errors.Is/As

Bolt.new
Bolt.new

Bolt.new是一个免费的AI全栈开发工具

下载

示例:批量更新用户返回结构化错误

type BatchUpdateError struct {
    FailedIDs []int64
    Cause     error // 底层原因(可选)
}

func (e *BatchUpdateError) Error() string {
    return fmt.Sprintf("failed to update %d users: %v", len(e.FailedIDs), e.Cause)
}

func (e *BatchUpdateError) Unwrap() error { return e.Cause }

// 使用
if len(failed) > 0 {
    return &BatchUpdateError{FailedIDs: failed, Cause: firstErr}
}

这样调用方能直接访问 .FailedIDs 做重试或日志,也能用 errors.Is 判断是否由数据库超时导致。

何时选 Join,何时选自定义?

  • 只需“知道哪些错了”,且错误语义相近 → 用 errors.Join
  • 需要暴露额外字段、做差异化处理、或错误之间有主次关系 → 自定义结构
  • 想兼容标准错误工具链(如日志库自动展开、调试器显示)→ 两者都支持,但自定义需正确实现 Unwrap
  • 性能敏感且错误数量极大(数千以上)→ errors.Join 内部是链表,大量错误可能影响遍历效率;此时可考虑只保留前 N 个或聚合统计

小技巧:组合使用更灵活

不必二选一。例如在自定义错误中,把子错误用 errors.Join 合并后再存入字段:

type ValidationErrors struct {
    FieldErrors map[string]error // 字段级错误
    GlobalErr   error            // 其他非字段错误(如网络超时)
}

func (e *ValidationErrors) Error() string {
    return "validation failed"
}

func (e *ValidationErrors) Unwrap() error {
    // 合并所有子错误供 errors.Is 使用
    errs := make([]error, 0, len(e.FieldErrors)+1)
    for _, err := range e.FieldErrors {
        errs = append(errs, err)
    }
    if e.GlobalErr != nil {
        errs = append(errs, e.GlobalErr)
    }
    return errors.Join(errs...)
}

这样既保持结构清晰,又不失标准错误生态的便利性。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

178

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

226

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

338

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

391

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

196

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

191

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

192

2025.06.17

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.8万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号