err == nil 是最正确、最直接的判空方式,因 Go 的 error 接口约定成功返回 nil,该判断语义清晰、性能最优且无副作用,其他方式如 interface{} 转换或 errors.Is(err, nil) 均错误或非法。

err == nil 就是最正确、最直接的判空方式,无需额外包装或转换。
为什么 err == nil 是唯一推荐方式
Go 的 error 是接口类型,nil 表示“无错误”,这是整个生态的契约。标准库、主流框架、几乎所有规范函数都严格遵循「成功返回 nil,失败返回非 nil error」这一约定。
-
err == nil判断的是接口值本身是否为零值,语义清晰、性能最优、无副作用 - 不需要转成
interface{}再比较——那是典型陷阱:一旦把error赋给interface{}变量,哪怕原err是nil,接口值也可能非空(因底层有 concrete type),导致== nil失效 -
errors.Is(err, nil)是非法调用(编译报错),errors.As(err, &nil)同样不合法,别被误导
常见踩坑场景与修复
这些写法看着“更泛化”,实则引入风险:
- ❌ 错误:把
error存进map[string]interface{}或结构体字段后再判空data := map[string]interface{}{"err": err} if data["err"] == nil { /* 假设 err 是 nil,这里仍可能为 false */ } - ❌ 错误:用
fmt.Printf("%v", err)或日志库自动字符串化前未判空
若err是自定义类型且Error()方法 panic,则err != nil检查虽通过,但打印时直接崩溃 - ✅ 正确:始终在原始返回位置立刻判断
data, err := os.ReadFile("config.json") if err != nil { log.Fatal(err) // 或其他处理 } // 后续逻辑直接写在这里,不套 else
什么时候不该只看 err == nil?
判空只是第一步。业务上还需进一步区分错误性质,此时才轮到 errors.Is 和 errors.As:
- 需要确认是不是某个预定义错误变量(如
sql.ErrNoRows、fs.ErrNotExist)→ 用errors.Is(err, sql.ErrNoRows) - 需要提取底层错误字段(如
*os.PathError的Path或Op)→ 用errors.As(err, &pathErr) - 但注意:这两个函数前提都是
err != nil;对nil调用它们会直接 panic 或返回 false,不能替代判空
最常被忽略的一点是:判空必须发生在 error 值尚未被隐式装箱(比如塞进 interface{}、传给泛型函数、或被日志中间件提前格式化)之前。一旦脱离原始上下文,== nil 就不再可靠。










