go中指针解引用前必须判空,因nil指针解引用会panic;接口藏nil指针时i==nil为false,需双保险检查;map/slice的nil行为与指针不同,应按语义判断;构造函数和初始化习惯比事后判空更有效。

指针解引用前必须用 p == nil 判断
Go 中指针的零值就是 nil,它不指向任何内存地址。一旦对 nil 指针执行 *p、p.Field 或 p.Method(),程序立刻 panic:runtime error: invalid memory address or nil pointer dereference。
这不是编译错误,而是在运行到那一行才崩溃——所以特别容易漏掉。
- 函数接收
*User参数时,第一句就该写if u == nil { return } - 结构体方法定义为指针接收者时,方法体内仍要判空:
if u == nil { return "Unknown" },否则var u *User; u.Greet()直接挂 - 不要依赖“调用方一定传了非 nil”,尤其是 HTTP handler、配置解析、数据库查询返回值这类外部输入场景
接口变量里藏了个 nil 指针,i == nil 会失效
这是最隐蔽的坑:一个 nil 的结构体指针赋给接口后,接口本身不等于 nil。
例如:var u *User; var i interface{} = u,此时 i == nil 是 false(因为接口有类型 *User),但 u 确实是 nil。后续若做类型断言或调用方法,照样 panic。
立即学习“go语言免费学习笔记(深入)”;
- 正确检查方式是双保险:
if i == nil || reflect.ValueOf(i).IsNil() - 更推荐的设计是:避免把可能为
nil的指针直接塞进接口;优先用值类型,或封装成显式可空结构(如type UserOpt struct { Value *User }) - 如果必须支持,文档里得写清楚“允许传
nil”,并在使用处加防护
map 和 slice 的 nil 判断不能套用指针逻辑
nil 切片和 nil map 虽然也用 == nil 判断,但行为和指针完全不同——它们某些操作是安全的,某些则不是。
-
nil切片:len(s)、cap(s)、for range s都安全;但s[0]或s[i] = x会 panic;append(s, x)可以正常工作(自动分配底层数组) -
nilmap:len(m)安全,但m["k"] = v或v, ok := m["k"]都会 panic;必须先m = make(map[string]int) - 函数接收
map或slice参数时,别只看== nil,要结合业务判断是否允许空——比如用len(s) == 0更贴近语义
构造函数和初始化习惯比技巧更重要
很多 nil 错误其实源于“没初始化就用”,而不是“用了没判空”。防御性编程从源头开始更有效。
- 声明即初始化:
u := &User{}或u := new(User),而不是var u *User后直接访问字段 - 提供
NewUser()类构造函数,确保成功路径返回非nil,失败路径返回(nil, err) - 结构体嵌套指针字段(如
Profile *Profile)必须显式初始化,不能靠默认nil - 循环中取地址要小心:
for _, v := range nums { ptrs[i] = &v }会导致所有指针指向同一个变量;应改用vCopy := v; ptrs[i] = &vCopy
真正难防的不是单点 nil,而是跨函数、跨 goroutine、跨接口传递过程中,nil 值被层层包裹又悄然隐去类型信息——这时候光靠 == nil 不够,得靠设计约束和静态检查工具(如 staticcheck 或 NilAway)补位。










