Go 1.13+ 不推荐使用 errors.Wrap 是因为它返回的错误类型不兼容标准库的包装检查逻辑,导致 errors.Is 和 errors.As 失效;应改用 fmt.Errorf("msg: %w", err)。

errors.Wrap 为什么在 Go 1.13+ 中不再推荐直接使用
Go 1.13 引入了原生错误包装机制(fmt.Errorf 的 %w 动词),标准库 errors 包也新增了 errors.Unwrap、errors.Is、errors.As 等函数。第三方库如 github.com/pkg/errors 的 Wrap 已逐渐被弃用——它返回的错误类型不兼容标准库的包装检查逻辑,导致 errors.Is 或 errors.As 失效。
如果你还在项目里用 pkg/errors.Wrap,升级到 Go 1.13+ 后务必替换,否则链式错误判断会静默失败。
- 旧写法(不推荐):
pkg/errors.Wrap(err, "failed to open config") - 新写法(推荐):
fmt.Errorf("failed to open config: %w", err) - 注意:
%w只能出现在格式字符串末尾,且仅接受一个error类型参数
如何正确用 fmt.Errorf 包装并保留原始错误
用 %w 包装后,原始错误被嵌入为“原因”,可通过 errors.Unwrap 获取下一层,也可用 errors.Is 跨多层匹配目标错误值(比如 os.ErrNotExist)。
示例:
立即学习“go语言免费学习笔记(深入)”;
err := os.Open("config.yaml")
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
- 这个返回的错误可被
errors.Is(err, os.ErrNotExist)正确识别 - 但
errors.Is(err, errors.New("loading config"))不会命中——Is只比对底层原因,不比对外层消息 - 若需提取原始错误做类型断言,用
errors.As(err, &target),不是err.(*os.PathError)
errors.Is 和 errors.As 的行为边界在哪
这两个函数只沿 %w 构建的包装链向下查找,不会解析错误消息字符串,也不支持自定义的 Unwrap() 方法(除非你手动实现且返回非 nil error)。
BIWEB 门户版几经周折,最终与大家见面了。BIWEB门户版建立在ArthurXF5.8.3底层上,有了更加强大的功能。 BIWEB WMS v5.8.3 (2010.1.29) 更新功能如下: 1.修正了底层getInfo方法中的调用参数,做到可以根据字段进行调用。 2.修正了栏目安装和卸载后,跳转链接的错误。 3.修正所有栏目分类系统,提交信息页面错误。 4.新增后台删除信息后仍停留原分
-
errors.Is(err, target):逐层调用Unwrap(),只要某一层==target就返回 true -
errors.As(err, &v):逐层尝试类型断言,成功则将值赋给v并返回 true - 如果错误是用
fmt.Errorf("xxx: %v", err)(注意是%v),则链被截断,Is/As查不到原始错误 - 多个
%w不允许:fmt.Errorf("%w and %w", err1, err2)是编译错误
自定义错误类型怎么支持标准包装协议
如果你实现自己的错误类型并希望它能参与标准包装链(比如被 %w 接收、被 errors.Is 识别),必须满足两个条件:
- 实现
Unwrap() error方法,返回内部嵌套的 error(可以是 nil) - 如果想让
errors.As能转成你的类型,还需确保该类型本身可被断言(即导出、非接口)
例如:
type ConfigError struct {
msg string
code int
err error // 原始错误
}
func (e *ConfigError) Error() string { return e.msg }
func (e *ConfigError) Unwrap() error { return e.err }
这样构造:&ConfigError{msg: "invalid format", err: json.SyntaxError{}},就能被 errors.Is 和 errors.As 正常处理。
容易忽略的一点:Unwrap() 返回 nil 表示包装链终止;返回非 error 值或 panic 会导致 Is/As 行为异常——这点在调试深层错误时很难定位。









