← 中文资源

简体中文版本

Go — 空指针解引用崩溃

从堆栈定位空指针解引用,检查被忽略的错误、map 查找和接口 nil,并用显式错误处理与回归测试修复。

阅读英文原文

症状

出现 panic: runtime error: invalid memory address or nil pointer dereference;服务退出或 HTTP 处理器返回 500 与堆栈;只有在依赖返回错误或查找未命中时出现。

诊断

从堆栈最内层应用帧开始阅读:

go test ./... 2>&1 | grep -B5 -A10 'nil pointer'

最顶部的应用帧指出确切的解引用位置,记录文件与行号。用 go test -race -run TestName -v ./... 复现并检查并发访问。然后检查该位置附近的错误返回与 map 查找:

grep -n 'err\|, ok :=\|return nil' path/to/file.go

被忽略的错误或缺失的 ok 检查通常解释了 nil 如何到达解引用点。

根因

Go 在解引用 nil 指针时 panic。值变成 nil 的原因包括忽略错误、查找未命中、构造函数返回 nil,或接口中持有 nil 具体值却与 nil 比较不相等。

修复

user, err := store.FindUser(ctx, id)
if err != nil {
    return "", fmt.Errorf("find user %s: %w", id, err)
}
if user == nil {
    return "", ErrUserNotFound
}
return user.Email, nil

检查错误后再使用结果;map 与类型断言使用双返回值;在 nil 时提前返回;使用前初始化指针。如果 nil 是合法值,应显式保护解引用并定义降级行为。

验证

为产生 nil 的输入添加回归测试并运行 go test -race;确认处理器返回定义好的错误而不是 panic;日志包含操作与标识符,而不只是“nil pointer”。

风险提示

recover() 可以把 panic 变成 500 并隐藏根因,只应在进程或请求边界配合日志与指标使用,不能作为主要的 nil 检查手段。