struct变量不能赋nil,因其是值类型且无nil状态;需用*person等指针类型表达“可空”,并注意解引用前必须判nil以防panic。

struct 变量不能赋 nil,编译直接报错
Go 中 struct 是值类型,没有 nil 状态。写 var p Person 或 p := Person{},得到的永远是一个合法、内存布局完整的实例,哪怕所有字段都是零值。一旦你写 p = nil,编译器立刻报错:cannot use nil as Person value in assignment。
常见错误现象:
- 把 Java/C++ 习惯带进来,以为结构体变量可以“置空”
- JSON 反序列化后想用
if p == nil判断是否有效,结果连编译都过不了 - 误以为
Person{}和nil等价,导致逻辑分支漏判(比如数据库查不到时想返回“空”,却返回了全零结构体)
*Person 才是表达“可空”的正确类型
真正能承载“未设置 / 已清除 / 不存在”语义的,是结构体指针类型 *Person。它的零值就是 nil,支持 == nil 比较,也支持显式赋 nil。
实操建议:
- 定义变量时就声明为指针:
var p *Person,而不是var p Person - 初始化用
&Person{}(推荐,可填字段)或new(Person)(全零值),不是Person{} - 清空时直接
p = nil,安全且语义清晰 - 调用方法前必须检查:
if p != nil { p.DoSomething() },否则可能 panic
注意:即使方法接收者是值类型(func (p Person) Method()),传入 nil 指针也会 panic——因为 Go 在调用前先解引用再复制,所以检查不能省略。
解引用前不判 nil 就 panic
nil 指针本身合法,不会崩溃;panic 发生在你试图解引用它的那一刻:写 *p、访问 p.Field、调用 p.Method(),都会触发 panic: invalid memory address or nil pointer dereference。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
哪些操作必须前置判 nil?
- 结构体字段访问:
u.Profile.Name(若u.Profile == nil) - map 写入:
m["k"] = v(若m == nil) - channel 收发:
或 <code>close(ch)(若ch == nil) - 接口方法调用:
w.Write(b)(若w底层值为nil)
len(s)、cap(s) 对 nil 切片安全;if p == nil 安全;但 p != nil && *p 是竞态写法,应拆成两步判断。
JSON 序列化/反序列化时零值陷阱
默认情况下,json.Marshal 会把 nil 指针字段序列化为 null,而零值结构体字段(如 Person{})会序列化为完整对象({"Name":"","Age":0})。这在 API 交互和数据库更新中极易引发歧义。
解决思路:
- 对需要区分“未提供”和“明确设为空”的字段,一律使用指针类型(
*string、*int、*time.Time) - 配合
omitemptytag:如Name *string `json:"name,omitempty"`,这样nil字段不出现,非nil零值仍会输出(除非额外处理) - 避免混用:不要一个字段用
string,另一个同级字段用*string,语义不一致容易埋坑
最易被忽略的一点:ORM(如 GORM)中,nil 指针字段通常被解释为“跳过更新”,而零值结构体字段会被当作“更新为零”,这个差异在 upsert 场景下会导致数据意外覆盖。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










