errors.Is 和 errors.As 是 Go 1.13 引入的必备错误处理工具,用于可靠判断和提取多层包装错误;必须用 errors.Is 判断是否等于标准或自定义错误变量,用 errors.As 提取底层具体类型实例。

errors.Is 和 errors.As 是 Go 1.13 引入的错误处理核心工具,用来替代老旧的 == 或类型断言,解决多层包装错误(如 fmt.Errorf("xxx: %w", err))下的判断与提取问题。它们不是“锦上添花”,而是现代 Go 错误处理的必备基础——不用它们,if err == io.EOF 或 _, ok := err.(*os.PathError) 在错误被包装后会直接失效。
什么时候必须用 errors.Is?
当你需要判断一个错误是否“等于”某个已知错误值(比如标准库预定义错误、自定义错误变量),且该错误可能被 %w 包装过时,errors.Is 是唯一可靠方式。
-
io.EOF、os.ErrNotExist、sql.ErrNoRows等标准错误变量,都应通过errors.Is(err, io.EOF)判断,而非err == io.EOF - 自定义错误变量(非指针类型)也能被正确识别:
var ErrTimeout = errors.New("timeout")→errors.Is(err, ErrTimeout)成立 - 如果错误链中任意一层是目标值(或实现了
Is(target error) bool方法并返回true),errors.Is就返回true - 注意:
errors.Is(err, nil)返回false,哪怕err是nil;判断空错误仍要用err == nil
什么时候必须用 errors.As?
当你需要从错误链中提取某个具体类型的错误实例(例如获取底层 *os.PathError 的 Path 字段),且该错误可能被多层包装时,errors.As 是安全提取的唯一途径。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 传入一个指向目标类型的指针变量,
errors.As会尝试将错误链中第一个匹配该类型的错误赋值给它:var pathErr *os.PathError; if errors.As(err, &pathErr) { ... } - 只匹配具体类型,不匹配接口(除非该接口实现了
As(interface{}) bool方法) - 如果错误链中没有该类型,
errors.As返回false,且目标变量保持原值(不会被置零) - 不能传值类型(如
os.PathError)或接口类型(如error)的地址,否则编译失败或行为未定义
errors.Is 和 errors.As 常见踩坑点
这两个函数看似简单,但实际使用中高频出错,根源在于对“错误链”和“包装机制”的理解偏差。
- 误以为
errors.Is(err, fmt.Errorf("xxx"))有效 —— 动态构造的错误值无法被Is匹配,必须用变量或标准库导出的错误常量 - 对
errors.As传入非指针(如errors.As(err, pathErr))会导致编译错误:cannot use pathErr (type *os.PathError) as type interface {} - 忽略
errors.As的返回值直接使用目标变量 —— 若匹配失败,变量仍是零值或旧值,可能引发 panic 或逻辑错误 - 在循环中反复调用
errors.As提取同一类型,却没意识到它只返回错误链中“第一个”匹配项;若需遍历所有包装层,得手动用errors.Unwrap -
errors.Is不支持子字符串匹配或模糊匹配,不要试图用它做错误消息解析
真正难的不是调用这两个函数,而是写出能被它们正确识别的错误链:所有包装必须用 %w,自定义错误类型若需参与 Is 或 As 判断,得主动实现 Is 或 As 方法。漏掉 %w 或写成 %s,整条链就断了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










