nil是指针、切片、映射、通道、函数、接口六种引用类型的合法零值,而非通用“空”;int、string、struct等类型不可与nil比较,否则编译报错。

nil 不是“空”,而是六类引用类型的零值;零值才是所有变量的默认初始状态。用 == nil 判断变量是否“为空”在大多数情况下是错的,编译直接报错或逻辑失效。
哪些类型能和 nil 比较?
只有指针、切片、映射、通道、函数、接口这六种类型支持 == nil 比较。其他类型如 int、string、struct、time.Time 都不能和 nil 比较——写 s == nil 会触发 invalid operation: s == nil (mismatched types string and nil)。
常见错误示例:
-
var s string; if s == nil→ 编译失败 -
var t time.Time; if t == nil→ 编译失败(time.Time是结构体) -
var p *int; if p == nil→ 合法,且为真 -
var m map[string]int; if m == nil→ 合法,且为真
nil 切片 vs 空切片:len(s) == 0 才是判断“空”的安全方式
一个切片变量可以是 nil,也可以是非 nil 但长度为 0。两者都满足 len(s) == 0,但底层行为不同:
-
var s []int→s是nil,cap(s)和len(s)都为 0,append(s, 1)安全 -
s := []int{}或s := make([]int, 0)→s非nil,同样len(s) == 0,但 JSON 编码可能输出[]而非null(取决于 encoder 设置) -
if s == nil会漏掉第二种情况;if len(s) == 0覆盖全部“空”语义
接口的 nil 判断最容易翻车
接口变量由动态类型 + 动态值组成。即使内部值是 nil 指针,只要类型信息存在,接口本身就不为 nil:
-
var err error = (*os.PathError)(nil)→err != nil,因为接口持有*os.PathError类型 -
if err == nil在标准error返回中是安全的,因为errors.New或nil返回都保证接口整体为nil - 但自定义接口如
type MyI interface{ Foo() },若你赋值var x MyI = (*MyStruct)(nil),则x == nil为 false
真正想判断“有没有有效值”,应优先用 reflect.ValueOf(v).IsNil()(仅对可判空类型),或明确设计 API 返回值约定。
方法调用时 nil 接收者不一定 panic
是否 panic 取决于方法体内是否解引用接收者:
-
func (s *T) Get() string { return "ok" }→var t *T; t.Get()合法,不 panic -
func (s *T) Name() string { return s.name }→t.Name()触发invalid memory address or nil pointer dereference -
func (t T) Copy() T(值接收者)→ 永远不 panic,但若t是零值结构体,字段仍是零值(如""、0)
这个细节常被忽略:nil 指针能调用某些方法,不代表它“安全”,只代表当前没碰内存。一旦逻辑扩展,就容易突然崩溃。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











