go中nil指针是合法零值,解引用(*p、p.field、p.method())时才panic;接口nil需类型和值双空;map、channel、函数、接口方法调用前必须判nil。

Go 中 nil 指针不是“空指针异常”,而是合法零值
nil 指针本身不会崩溃,panic: invalid memory address or nil pointer dereference 一定发生在你试图解引用它的那一刻——比如写 *p、访问 p.Field 或调用 p.Method()。Go 不提供自动空安全导航(如 JavaScript 的 ?.),也不在运行时静默跳过,它选择明确失败。
- 声明未初始化的指针默认就是
nil:var u *User→u == nil为 true -
struct类型变量永远不为nil,if s == nil是编译错误 - 接口是否为
nil看的是「类型 + 值」双空:var u *User; var i interface{} = u→i != nil(类型存在,值为nil),此时直接断言并调用方法仍会 panic
哪些操作必须判 nil 才能避免 panic
不是所有用指针的地方都要检查,但以下场景只要面对 nil 就必然崩溃,必须前置判断:
- 解引用:
*p(p为*T) - 结构体字段访问:
u.Profile.Name(若u.Profile == nil) - map 写入:
m["k"] = v(m == nil) - channel 收发或关闭:
或 <code>close(ch)(ch == nil) - 函数调用:
f()(f == nil) - 接口方法调用:
w.Write(b)(w底层值为nil)
注意:len(s)、cap(s) 对 nil 切片安全;if p == nil 安全;但 p != nil && *p 仍是竞态写法,应拆成两步。
方法接收者为 nil 时能调用,但很危险
Go 允许在 nil 指针上调用方法(只要接收者是 *T),但这只是语法允许,不代表逻辑安全。
立即学习“go语言免费学习笔记(深入)”;
- 如果方法内部没访问字段或解引用,比如只返回常量或做类型转换,它确实不会 panic
- 一旦方法里出现
u.Name或u.Profile.ID,而u或u.Profile是nil,立刻崩溃 - 值接收者方法(
func (u User) Name() string)在nil指针上传入时,Go 会自动解引用并复制零值——看似安全,实则掩盖了上游传入nil的问题
推荐写法是早检查:if u == nil { return "" },而不是靠方法签名“兜底”。
构造和返回指针时最常漏掉的 nil 检查
很多 panic 不来自使用方,而来自构造逻辑本身返回了未预期的 nil:
-
func NewUser(name string) *User没有 error 返回,又在name == ""时悄悄返回nil→ 调用方一解引用就崩 -
var u *User; return u显式返回未初始化指针,等价于return nil,但语义模糊 - 返回局部变量地址虽被逃逸分析“兜住”,但易误导人以为可栈上分配,实际应优先返回值或显式
new(User) - 把
nil指针赋给接口后直接用:var w io.Writer = (*bytes.Buffer)(nil)→w.Write()panic,因为接口非nil,但底层值是nil
真正难防的不是 nil,而是那个你以为“不可能为 nil”却偏偏是 nil 的指针——尤其跨包、跨层、从 JSON 解析或数据库查出来的结构体指针字段。










