go中空指针解引用才会panic,关键是在使用前检查nil:调用返回指针的函数后须先判err再判指针非nil,循环中取地址需避免变量复用导致指针指向同一终值。

Go 里空指针本身不 panic,只有解引用 nil 指针时才会崩溃——比如写 *p、p.Field 或 p.Method()。所以关键不是“消灭 nil”,而是“不让 nil 被解引用”。
调用返回指针的函数后必须检查 error 和 nil
像 http.Get()、json.Unmarshal()、ORM 查询方法等,常返回 *T 和 error。错误优先(error-first)是 Go 的约定:先看 err != nil,再用指针。
- 错误现象:
panic: runtime error: invalid memory address or nil pointer dereference出现在resp.Body.Close()或user.Name - 正确顺序:必须在任何解引用前完成双检查
- 别写成:
resp, _ := http.Get(url); resp.Body.Close()——_丢掉 error 就等于埋雷 - 推荐写法:
if err != nil { return err }后直接写主逻辑,不嵌套
解引用指针前加显式 nil 判断
哪怕你“觉得它不该是 nil”,也要加 if p != nil。Go 不做隐式安全假设,且静态分析工具(如 staticcheck)会报未判空警告。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 结构体字段访问:
if user != nil { fmt.Println(user.ID) } - 方法调用:
if client != nil { client.Do(req) } - 注意接口的 nil 判断更严格:接口变量为
nil需同时满足类型和值都为nil,不能只靠if i == nil简单判断 - 值接收器方法可被
nil接口调用,但指针接收器方法不行——这点容易被忽略
避免循环中取地址导致所有指针指向同一终值
for 循环变量复用是高频陷阱,表面没报错,但所有指针实际都指向循环结束后的最终值。
- 错误写法:
for i := 0; i → 所有 <code>*ptrs[i]都是3 - 正确做法:在循环内创建副本,例如
val := i; ptrs = append(ptrs, &val) - 切片元素赋值也适用:如果存的是
*struct,确保每次 append 的是独立地址,而非反复取同一个变量的地址 - go vet 和 golangci-lint 默认会捕获这类问题,建议接入 CI
初始化指针比放任零值更可控
局部指针变量默认是 nil,但有些场景下主动初始化反而更安全,尤其当函数签名已承诺返回非空指针时。
- 工厂函数返回指针:
func NewConfig() *Config { return &Config{Timeout: 30} } - 函数返回指针类型时,在函数开头初始化:
func GetUser() *User { return &User{} },而非留空让调用方承担判空成本 - 慎用
new(T):它只做零值初始化,不如字面量&T{}清晰;且对 map/slice 等类型,new(map[string]int) 返回的是*map,不是可直接用的 map - 数据库查询常见坑:
var u *User; db.First(&u, id)中u是**User,易误写成u.Name导致 panic —— 正确应是(*u).Name或改用值接收
最危险的不是 nil,而是你以为它不是 nil 却没验证。Go 的零值设计本意是让 nil 显而易见,但这也意味着你得亲手把它拦在解引用之前——没有自动防御,只有主动检查。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










