go语言:nil说明 作者:马育民 • 2026-10-05 09:44 • 阅读:10000 # 介绍 **nil 是 Go 的预定义标识符,不是关键字,代表「零值」,只能赋值给特定类型的变量;nil 本身没有类型,会随上下文推导类型。** ### 类比 类似Java的 `null` # 1. 哪些类型可以为 nil 只有下面这 6 种引用/指针类型,它们的零值才是 `nil`: 1. 指针 `*T` 2. 切片 `[]T` 3. map `map[K]V` 4. 通道 `chan T` 5. 函数 `func()` 6. 接口 `interface{}` ✅ 其他类型零值**不是 nil**: - int → 0 - string → "" - bool → false - 结构体 → 所有字段置零 ```go var a *int // nil var b []int // nil var c map[string]int // nil var d chan int // nil var e func() // nil var f interface{} // nil var g int // 0,不是 nil var h string // "",不是 nil ``` # 2. nil 没有类型,动态推导 `nil` 是无类型常量,编译器会根据接收变量确定 nil 的类型。 ```go var p *int = nil var s []int = nil // p 和 s 的 nil 不是同一个东西,类型不同 ``` ### 坑 **不能直接写 `nil == nil`**,编译器报错,因为缺少类型信息。 ```go // invalid operation: nil == nil (untyped nil == untyped nil) if nil == nil { } ``` # 3. 接口的 nil:最容易踩坑! 接口变量由两部分组成:**动态类型 + 动态值** > 接口 == (type, value) 只有 **type 和 value 同时为 nil**,接口变量才等于 nil。 如果 type 不为 nil,value 是 nil,接口**不等于 nil**。 示例: ```go type MyErr struct{} func (e *MyErr) Error() string { return "err" } func test() error { var e *MyErr = nil // value是nil,类型是*MyErr return e // 返回接口:( *MyErr, nil ) } func main() { err := test() fmt.Println(err == nil) // false!! } ``` 解释: 接口变量 err 的动态类型是 `*MyErr`(不为nil),动态值是 nil,所以 `err != nil`。 ✅ 修复:返回真正 nil 接口 ```go func test() error { var e *MyErr = nil if e == nil { return nil // 返回 (nil, nil) 的接口 } return e } ``` # 4. 各类型 nil 的行为差异 ### 指针 nil - `var p *int = nil` - 不能解引用 `*p` → panic - 可以取地址 `&p` ### 切片 nil ```go var s []int = nil fmt.Println(len(s)) // 0 fmt.Println(cap(s)) // 0 ``` ✅ **nil 切片可以调用 len、cap,可以 append** append nil slice 会自动分配底层数组,不会panic。 ```go var s []int = nil s = append(s, 1) // 正常,s 变成 [1] ``` > nil切片 和 空切片 `[]int{}`:len、cap都是0,但底层数组指针不一样。 ### map nil ```go var m map[string]int = nil fmt.Println(m["a"]) // 可以读,返回值类型零值 m["a"] = 1 // panic: assignment to entry in nil map ``` ✅ 读 nil map 没问题;❌ **写 nil map 直接 panic** ### channel nil ```go var ch chan int = nil <-ch // 阻塞,永远等待 ch <- 1 // 阻塞,永远等待 close(ch) // panic: close of nil channel ``` > nil channel 收发都会永久阻塞,不能 close。 ### func nil ```go var f func() = nil f() // panic: call of nil function ``` nil函数变量调用会panic。 # 5. nil 比较规则 1. **同类型**的 nil 值可以比较:`var p1,p2 *int = nil; p1 == p2 → true` 2. **不同类型 nil 不能直接比较**:`var p *int; var s []int; p == s` 编译报错 3. 接口比较:按上面的(type,value)规则 原文出处:/show_1GW4AeRZYRLb.html