会执行:panic 时已注册的 defer 必定执行,按后进先出顺序;defer 不替代错误处理,需先判错再 defer;循环中 defer 会延迟至函数结束,易致资源泄漏;recover 必须在 defer 内调用才能捕获 panic。

defer 会执行吗:panic 时的释放行为
会执行,但仅限于 panic 发生前已注册的 defer。Golang 的 defer 是栈式后进先出(LIFO)执行,且无论函数是正常 return 还是 panic,只要该 defer 语句已执行到(即所在代码路径被走到),它就一定会在函数返回前运行。
常见误解是“panic 会跳过 defer”,实际不会——除非 panic 发生在 defer 注册之前(比如在函数开头就 panic),否则所有已注册的 defer 都会触发。
- 如果在
defer后面又调用了会 panic 的函数,前面注册的defer仍会执行 -
defer中若再 panic,会覆盖前一个 panic(除非用recover捕获) - 多个
defer按注册逆序执行:最后注册的最先执行
文件句柄没关:defer + os.Open 的典型漏写
很多人写 os.Open 后只 defer file.Close(),却忘了检查 err。一旦打开失败,file 是 nil,调用 Close() 会 panic(panic: runtime error: invalid memory address or nil pointer dereference)。
正确做法是:先判错,再 defer;或用带 err-check 的封装逻辑。
file, err := os.Open("config.txt")
if err != nil {
return err // 不 defer,避免 nil.Close()
}
defer file.Close() // 此时 file 必然非 nil
- 永远不要对可能为 nil 的值直接 defer 方法调用
- 如果资源获取和使用分多步(如 Open → Stat → Read),建议每步都做 err 检查,只对确定成功的资源 defer 释放
-
defer不能替代错误处理,它只负责“成功获取后的兜底释放”
数据库连接泄漏:defer 在循环里失效的场景
在 for 循环中反复打开 DB 连接并 defer conn.Close(),会导致所有连接直到函数结束才批量关闭——这不是资源及时释放,而是堆积泄漏。
因为 defer 绑定的是当前函数作用域的退出时机,不是每次循环迭代的结束。
for _, id := range ids {
conn, err := db.OpenConn()
if err != nil {
continue
}
defer conn.Close() // ❌ 全部 defer 到外层函数 return 才执行
// ...
}
- 循环内需即时释放?改用显式
conn.Close()并配合 err 检查 - 或把循环体抽成独立函数,让每次调用都有自己的 defer 生命周期
- 使用
sql.DB时优先走db.Query/Exec,由连接池自动管理,避免手动 Open/Close
recover 要放在 defer 里:捕获 panic 后继续释放
如果业务逻辑可能 panic(比如解析不可信 JSON、调用不稳定的外部服务),而你又希望即使 panic 也能确保清理动作完成,就得在 defer 中嵌套 recover() ——但注意顺序:recover 只能捕获当前 goroutine 中同一层 defer 链上的 panic。
func process() {
f, _ := os.Create("log.txt")
defer func() {
if r := recover(); r != nil {
log.Printf("recovered from panic: %v", r)
}
f.Close() // ✅ 即使 panic 也执行
}()
json.Unmarshal([]byte(`{`), &struct{}{}) // panic
}
-
recover()必须在defer函数内部调用才有效 - 不要在 defer 外层 recover,那捕不到
- recover 后程序继续执行 defer 剩余部分,所以清理逻辑放它后面是安全的
真正难的不是 defer 写法,而是判断哪些资源必须靠它兜底、哪些该由上层控制流保证释放——比如 context cancel、goroutine 生命周期、第三方库的 shutdown 顺序,这些往往比 defer 本身更易出错。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











