errors.is 仅识别标准库错误链,不兼容 pkg/errors.wrap;判断类型应使用 errors.as 或 os.is* 系列函数,而非 errors.is。

errors.Is 只能判断是否与某个特定错误(或其底层包装链)相等,不是万能的“错误类型检查”工具——它不识别接口、不看错误值的结构,只认 errors.Is 显式包装过的错误链。
为什么 errors.Is 有时返回 false,明明 err 是用 errors.Wrap 包装的?
因为 errors.Wrap(来自 github.com/pkg/errors)和标准库 errors.Unwrap 不兼容。Go 1.13+ 的 errors.Is 只识别标准库 fmt.Errorf 带 %w 动词包装的错误,或显式实现了 Unwrap() error 方法且返回非 nil 的自定义错误。
- 用
fmt.Errorf("failed: %w", originalErr)才能被errors.Is正确追溯 - 第三方库如
github.com/pkg/errors的Wrap返回的错误没有标准Unwrap(),errors.Is看不到里层 - 如果混用标准库和 pkg/errors,
errors.Is(err, target)很可能意外失败
如何安全地判断一个错误是否是 os.PathError 或 net.OpError?
直接用 errors.Is 判断底层错误是否为某类系统错误,往往不准——因为 os.PathError 和 net.OpError 本身不实现 Unwrap(),它们是“终端错误”,不会被 errors.Is 向下穿透。
- 想确认是否是文件不存在?用
os.IsNotExist(err),它内部做了类型断言 +errors.Is组合判断 - 想确认是否是连接被拒绝?用
errors.Is(err, syscall.ECONNREFUSED)(注意:需先import "syscall") - 通用做法:优先使用
os.Is*系列函数;没对应函数时,再考虑errors.As提取具体错误类型
errors.Is 和 errors.As 的关键区别在哪?
errors.Is 是“值相等”判断(类似 ==),errors.As 是“类型匹配”提取(类似 type assertion)。两者解决的问题完全不同,不能互相替代。
-
errors.Is(err, io.EOF)→ 判断 err 是否等于io.EOF或其任意包装版本 -
var pathErr *os.PathError; errors.As(err, &pathErr)→ 尝试从 err 链中找到第一个*os.PathError实例并赋值给pathErr - 误用
errors.Is想判断类型?永远返回 false —— 它不比较类型,只比错误值是否一致 - 性能上,
errors.Is最坏要遍历整个错误链,但通常链很短;errors.As同样遍历,但还要做类型反射匹配,略重一点
真正容易被忽略的是:errors.Is 对自定义错误类型的判断,完全依赖你是否在 Unwrap() 方法里正确返回下一层错误。少写一行 return e.cause,整条链就断了——它不会猜,也不会 fallback。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











