Go 的接口值是 (类型, 值) 的二元组。只有类型和值都为 nil 时,接口才等于 nil。把一个 nil 指针赋给接口,类型字段非 nil,接口判空就失败——这是 Go 面试和线上事故中的经典陷阱。
func getErr() error {
var e *MyError // nil 指针
return e // 返回时包装成 (type=*MyError, value=nil)
}
err := getErr()
fmt.Println(err == nil) // false!
解析:调用方看到 err != nil 以为出错去处理,实际 *MyError 是 nil,调用其方法可能 panic(除非方法做了 nil receiver 保护)。规范做法:函数内部应显式 return nil,返回接口零值,而不是返回类型化的 nil 指针。
避免方式:
- 返回 error 或接口的函数,无错误时直接 return nil;
- 必须判断底层时可用 reflect.ValueOf(v).IsNil(),但要先确认 Kind 是指针类;
- 评审时警惕'先声明具体类型变量再作为接口返回'的写法。
追问方向:eface 与 iface 的结构差异、nil receiver 方法为何有时安全、接口动态分派。