interface{} == nil 判断动态类型和动态值是否均为 nil;仅当二者皆空时结果才为 true,否则即使值为 nil(如 *int(nil))也会返回 false。

interface{} == nil 到底在比什么
它在同时检查两个东西:动态类型是否为 nil,以及动态值是否为 nil。只有二者都为 nil,整个接口才等于 nil。
- 声明但未赋值的
var x interface{}→ 动态类型nil+ 动态值nil→x == nil为true -
var p *int; x := interface{}(p)→ 动态类型是*int(非nil),动态值是nil→x == nil为false -
err := (*os.PathError)(nil)赋给error接口后,err == nil也是false,因为类型*os.PathError已确定
为什么 if err == nil 通常能用,但自定义接口不能照搬
因为 error 是标准接口,且绝大多数错误返回逻辑都遵循“不返回带类型的 nil 值”这一约定——比如 fmt.Errorf("") 返回非 nil 接口,nil 错误一定来自显式 return nil,此时动态类型和动态值确实都为空。
- 你写的
type Service interface{ Do() },如果有人写var s Service = (*myImpl)(nil),那s == nil就是false - HTTP handler 中
if r.Body == nil永远是false,因为r.Body类型是io.ReadCloser,即使底层是nil,接口本身也非nil - 判断标准:看值是不是通过
return nil或未初始化变量直接得来;而不是看它“看起来空不空”
怎么安全判断接口里装的值是不是零值
用 reflect 比对底层类型的零值,而不是依赖 == nil。这是唯一能覆盖所有类型(包括 int、string、*T、[]byte)的通用方法。
- 先排除接口自身为
nil:if x == nil { return true } - 再用
reflect.ValueOf(x).IsNil()只适用于指针、map、slice 等可判nil的类型,对int或string会 panic - 稳妥做法是:
reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()),但注意性能开销;高频路径建议按类型分支处理 - 示例:
func IsZero(x interface{}) bool { return x == nil || reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()) }
最容易被忽略的坑:JSON 解码 + struct 字段为 nil 切片
Go 的结构体字段默认零值是 nil 切片,不是空切片;而 JSON 解码时若字段缺失,默认保持零值 —— 这导致 len(s.Tags) == 0 为 true,但 s.Tags == nil 也为 true;一旦你把它转成 interface{} 再传给某个函数,那个函数看到的是一个非 nil 接口,里面装着 nil 切片。
立即学习“go语言免费学习笔记(深入)”;
- 这种情况下,
if v == nil不成立,但v.([]string) == nil成立 —— 类型断言后才能看到真实状态 - API 响应中字段为
null时,json.Unmarshal默认设为nil,而非[]string{};别指望== nil能统一兜底 - 真正要判断“有没有数据”,优先用
len()或!= nil显式断言后再用,而不是依赖接口比较
nil 判断从来不是单维度的事,动态类型和动态值必须一起看;而“空”的语义,在不同上下文里根本不是一个东西。


















