一句话定义
nil是 Go 里"没有值 / 空引用 / 未指向任何对象"的零值------ 类似于
null,但规则更严格。
一、nil 到底能用在哪些类型上?
⚠️ 不是所有类型都能是 nil
✅ 可以是 nil 的类型(引用类型)
| 类型 | 说明 |
|---|---|
pointer |
指针 |
slice |
切片 |
map |
映射 |
channel |
通道 |
func |
函数 |
interface |
接口 |
go
var p *int = nil
var s []int = nil
var m map[string]int = nil
var ch chan int = nil
var f func() = nil
var i interface{} = nil
❌ 不能是 nil 的类型(值类型)
go
var a int = nil // ❌ 编译错误
var b string = nil // ❌
var c struct{} = nil // ❌
var d bool = nil // ❌
这些类型有明确的零值 (0、""、false),不需要
nil
二、nil ≠ "空",这是 Go 里最容易踩的坑
1️⃣ nil slice vs 空 slice
go
var s1 []int // nil
s2 := []int{} // 空 slice
区别:
| s1 | s2 | |
|---|---|---|
| 值 | nil | 非 nil |
| len | 0 | 0 |
| 可 append | ✅ | ✅ |
| s == nil | true | false |
go
fmt.Println(s1 == nil) // true
fmt.Println(s2 == nil) // false
👉 len 为 0 ≠ nil
2️⃣ nil map 不能写
go
var m map[string]int
m["a"] = 1 // ❌ panic
必须先初始化:
go
m := make(map[string]int)
m["a"] = 1 // ✅
3️⃣ nil pointer 不能解引用
go
var p *int
fmt.Println(*p) // ❌ panic
三、nil 在函数返回值里的经典用法
这是你现在写 Web / 文件系统一定会遇到的:
go
func readFile() ([]byte, error) {
if err != nil {
return nil, err
}
return data, nil
}
含义非常清晰:
- 成功:有 data,error 为 nil
- 失败:data 为 nil,error 不为 nil
👉 Go 的错误处理模式全靠 nil
四、最容易把人坑死的一种 nil(接口 nil)
这是 Go 面试/实战必考点。
看起来是 nil,其实不是
go
var p *int = nil
var i interface{} = p
fmt.Println(i == nil) // false ❗
原因:
interface =(动态类型 + 动态值)
只要"类型"不为 nil,interface 就不为 nil
正确判断方式
go
if i == nil {
// 真正的 nil
}
但如果你是从 interface 拿值:
go
if v, ok := i.(*int); ok && v == nil {
// v 是 nil 指针
}