Go 1.20+ 中错误链式处理核心是用 fmt.Errorf("%w", err) 包装以支持 errors.Unwrap/Is/As 追溯;避免 %v 丢失类型,慎用 pkg/errors;errors.Join 用于聚合多错误;%+v 可打印完整调用链。
Go 1.20+ 中用
的
动词包装错误
链式返回错误的核心是让下游能通过
或
/
向上追溯原始错误。从 Go 1.20 开始,
支持
(wrap)动词,这是最轻量、最标准的包装方式。
常见错误是写成
—— 这会丢失原始错误类型和堆栈,变成纯字符串。
正确写法:
只接受一个实现了
接口的值,且必须是最后一个参数
被包装的错误可通过
获取(只解一层),或用
判断是否包含某类错误
如果 err 是 nil,
会静默忽略,结果为非 error 值(即包装后仍是 nil),这点和
不同
用
合并多个错误并保持可遍历性
当一个操作可能触发多个独立失败(如并发调用多个服务),需要聚合错误又不想丢弃任一原因时,
是 Go 1.20 引入的官方方案。
它返回的 error 实现了
,支持递归展开,比手拼字符串或自定义 struct 更可靠。
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
立即学习
“
go语言免费学习笔记(深入)
”;
示例:
,后续可用
得到切片
会对所有子错误逐个调用
,任一匹配即返回 true
注意:若传入 nil,
会跳过;但若全为 nil,则返回 nil
不适用于需保留调用上下文的场景(它不自动加堆栈),此时应配合
分层包装
避免在中间层用
(来自 github.com/pkg/errors)
很多老项目还在用
的
,但它与标准库不兼容:其
返回的 error 不满足 Go 标准库的
签名(返回单个 error 而非可迭代结构),导致
/
在跨包调用时失效。
Go 1.13 引入的
和 Go 1.20 的
已覆盖全部需求,无需第三方包装器
如果依赖中仍含
,升级时要检查是否直接用了它的
/
;建议逐步替换为
特别注意:
在标准库 error 链上行为不可靠,不要混用
调试时用
查看完整错误链
标准库的
动词会打印错误链中每一层的文本 + 调用位置(前提是使用
包装,且运行时启用了
或 Go 1.21+ 默认开启的 stack trace 捕获)。
对比:
只输出最外层错误文本;
展开整个链并显示每层的文件/行号
该行为依赖
,在 CGO 环境或某些嵌入式目标下可能被裁剪,需确认构建环境
生产环境慎用
打印敏感路径或参数,建议日志中仅用
或提取关键字段
链式错误真正的难点不在怎么包,而在于什么时候不该包——比如对已知可恢复的错误(如
),直接处理而非层层包装,否则会让调用方难以区分语义。
fmt.Errorf%werrors.Unwraperrors.Iserrors.Asfmt.Errorf%wfmt.Errorf("failed to open file: %v", err)return fmt.Errorf("failed to open file: %w", err)%werrorerrors.Unwrap(err)errors.Is(err, targetErr)%w%verrors.Joinerrors.JoinUnwrap() []errorerr := errors.Join(errA, errB, errC)errors.Unwrap(err)errors.Is(err, someErr)IsJoinfmt.Errorf("%w", ...)errors.Wrapgithub.com/pkg/errorsWrapWrapUnwrap()errors.Iserrors.As%wJoinpkg/errorsWrapWithStackfmt.Errorf("%w", ...)pkg/errors.Cause(err)fmt.Printf("%+v", err)%+vfmt.Errorf("%w", ...)GODEBUG=gocacheverify=1fmt.Println(err)fmt.Printf("%+v", err)runtime/debug.Stack()%+v%vos.IsNotExist