介绍
nil 是 Go 的预定义标识符,不是关键字,代表「零值」,只能赋值给特定类型的变量;nil 本身没有类型,会随上下文推导类型。
类比
类似Java的 null
1. 哪些类型可以为 nil
只有下面这 6 种引用/指针类型,它们的零值才是 nil:
- 指针
*T - 切片
[]T - map
map[K]V - 通道
chan T - 函数
func() - 接口
interface{}
✅ 其他类型零值不是 nil:
- int → 0
- string → “”
- bool → false
- 结构体 → 所有字段置零
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 的类型。
var p *int = nil
var s []int = nil
// p 和 s 的 nil 不是同一个东西,类型不同
坑
不能直接写 nil == nil,编译器报错,因为缺少类型信息。
// invalid operation: nil == nil (untyped nil == untyped nil)
if nil == nil {
}
3. 接口的 nil:最容易踩坑!
接口变量由两部分组成:动态类型 + 动态值
接口 == (type, value)
只有 type 和 value 同时为 nil,接口变量才等于 nil。
如果 type 不为 nil,value 是 nil,接口不等于 nil。
示例:
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 接口
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
var s []int = nil
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
✅ nil 切片可以调用 len、cap,可以 append
append nil slice 会自动分配底层数组,不会panic。
var s []int = nil
s = append(s, 1) // 正常,s 变成 [1]
nil切片 和 空切片
[]int{}:len、cap都是0,但底层数组指针不一样。
map nil
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
var ch chan int = nil
<-ch // 阻塞,永远等待
ch <- 1 // 阻塞,永远等待
close(ch) // panic: close of nil channel
nil channel 收发都会永久阻塞,不能 close。
func nil
var f func() = nil
f() // panic: call of nil function
nil函数变量调用会panic。
5. nil 比较规则
- 同类型的 nil 值可以比较:
var p1,p2 *int = nil; p1 == p2 → true - 不同类型 nil 不能直接比较:
var p *int; var s []int; p == s编译报错 - 接口比较:按上面的(type,value)规则