安全,但仅限于接口类型变量直接比较;err == nil判断正确且推荐,误判多因错误被包装或转为其他接口;err != nil后调用err.Error()前需防panic;errors.Is/As对nil返回false且已防护;自定义错误需分层判空,避免用字符串比较判空。

Go中err == nil是否安全?
安全,但仅限于接口类型变量直接比较。Go的error是接口,nil表示该接口的动态类型和动态值均为nil。只要错误变量没被赋过非nil的具体错误实例(比如fmt.Errorf返回值),err == nil就是正确且推荐的判断方式。
常见误判场景:用指针接收器方法包装错误后忘记检查、或错误被转成其他接口(如fmt.Stringer)再比较,此时== nil可能失效。
为什么err != nil之后不能直接用err.Error()?
因为err.Error()方法本身可能 panic——某些自定义错误实现未校验内部字段,或在Error()里做了不安全操作(如解引用空指针)。虽然标准库错误不会这样,但第三方包或业务代码可能出问题。
稳妥做法:
立即学习“go语言免费学习笔记(深入)”;
- 先确认
err != nil - 再调用
err.Error()前,加一层防御性判断(例如检查是否实现了error接口,或用fmt.Sprintf("%v", err)代替) - 更推荐直接用
fmt.Printf("err: %v", err)输出,fmt包对nilerror有特殊处理,不会panic
使用errors.Is和errors.As时,err为nil会怎样?
两者都要求err是非nil的error接口值。如果传入nil,errors.Is(nil, target)返回false;errors.As(nil, &target)返回false且不修改target。它们内部已做nil防护,无需额外判断,但逻辑上你本就不该对nil error调用这两个函数——毕竟没错误时谈不上“是否是某类错误”或“能否转成某类型”。
典型错误写法:
if errors.Is(err, io.EOF) { ... } // err为nil时这行无害,但语义错:nil不是io.EOF
应确保只在err != nil分支中使用errors.Is/errors.As。
自定义错误类型里嵌套error字段时,如何正确判空?
例如:
type MyError struct {
Msg string
Cause error
}
这时MyError{Cause: nil}本身不是nil(它是结构体值),但它的Cause字段是nil。判空必须分层:
-
err == nil→ 判断整个错误变量是否为空接口 -
errors.Unwrap(err) == nil→ 判断是否可展开及展开后是否为空 - 若需访问
Cause,先断言:if e, ok := err.(*MyError); ok && e.Cause != nil
别依赖fmt.Sprint(err) == ""或err.Error() == ""来判断空,这些是语义判断,不是空值判断。
最易被忽略的是:把结构体错误当指针用,却忘了初始化——var e *MyError是nil指针,而e := &MyError{}是非nil但Cause字段为nil。这两者在err == nil判断中结果完全不同。










