Go中nil指针本身合法,仅解引用(*p、p.Field、p.Method())时触发panic;接口nil需类型和值双空;map、channel、函数、接口方法调用前必须判nil。

Go里没有“空指针异常”,只有nil指针解引用panic
Go语言中不存在Java或C++那种“空指针异常”机制,nil本身不是错误,但一旦对nil指针进行解引用(比如访问字段、调用方法),运行时立刻触发panic: runtime error: invalid memory address or nil pointer dereference。这个panic无法被recover捕获——除非它发生在goroutine里且你显式做了defer/recover,但主goroutine的nil解引用panic会直接终止程序。
如何提前检查nil指针避免panic
最直接有效的方式是在解引用前显式判断是否为nil。这不是防御性编程的妥协,而是Go的惯用法。
-
if p != nil是最基本、最安全的检查,适用于所有指针类型(*T、*sync.Mutex、自定义结构体指针等) - 方法接收者为指针时,方法内部仍需检查
nil——Go允许nil调用方法,但若方法体中访问了nil指向的字段,就会panic - 切片、map、channel、function、interface的零值也是
nil,但它们的使用方式不同:比如len(nilSlice)合法,而nilMap["key"]不会panic(返回零值),但nilMap["key"] = 1会panic
示例:
func printName(p *Person) {
if p == nil {
fmt.Println("person is nil")
return
}
fmt.Println(p.Name) // 安全
}
哪些场景最容易漏掉nil检查
实际代码中,以下几类操作是nil panic高发区,往往因“觉得不可能为nil”而跳过检查:
立即学习“go语言免费学习笔记(深入)”;
- 函数返回指针(如
json.Unmarshal反序列化到*T,若输入为空或格式错误,可能返回nil) - 接口类型断言后取指针:比如
val, ok := i.(interface{ GetID() int }); if ok { id := val.GetID() }——如果val是nil接口,调用GetID()会panic(因为底层是nil指针实现) - 第三方库API文档未明确说明是否可能返回
nil,但实际会(比如某些ORM的FindOne方法在无结果时返回nil) - 并发场景下,指针变量被多个goroutine读写,未加锁导致读到中间态
nil
用工具和测试主动暴露nil风险
靠人眼检查容易遗漏,应结合工具链降低风险:
-
go vet能发现部分明显问题,比如对nil接口调用方法(但不覆盖所有情况) - 静态分析工具如
staticcheck启用SA5011规则,可检测潜在的nil指针解引用路径 - 单元测试必须覆盖
nil输入分支——尤其对导出函数和方法,传入nil参数看是否panic,再决定是否加检查或文档注明“不允许nil” - 考虑用
golang.org/x/tools/go/analysis写自定义检查器,比如强制要求所有*T参数在函数入口处有!= nil判断(适合团队规范)
真正棘手的不是“怎么加检查”,而是“哪里该加”。很多panic发生在深层调用栈,源头传入的nil一路透传,直到某处突然解引用。所以关键不在最后一行代码,而在每层函数交接时,明确约定并验证指针的有效性。


















