go中defer按后进先出(lifo)顺序执行,即最后注册的最先执行;参数在defer语句出现时立即求值,非执行时求值。

多个 defer 为什么不是从上往下执行?
Go 里 defer 的执行顺序是后进先出(LIFO),也就是“最后注册的最先执行”。这不是 bug,而是设计使然:Go 把每个 defer 语句压入一个栈,函数退出时统一出栈执行。
常见错误现象:
写了一堆 defer,以为按代码顺序依次关闭资源,结果日志打印或文件关闭顺序反了,甚至因依赖关系出错(比如先关数据库连接,再关事务)。
- 所有
defer都在函数返回前触发,但顺序和书写顺序相反 - 哪怕中间有
return、panic,只要defer已注册,就一定会执行 - 想控制顺序?别靠写代码顺序,靠注册时机——把要先执行的
defer写在后面
defer 参数什么时候求值?为什么闭包里取不到循环变量?
defer 后面函数的参数,在 defer 语句**出现那一刻就求值完毕**,不是等到真正执行时才取。这是最常踩的坑之一。
使用场景:遍历资源做延迟清理、批量注册回调等。
- 错误写法:
for i := 0; i → 输出全是 <code>3 - 正确写法:
for i := 0; i → 输出 <code>0、1、2 - 本质是闭包捕获变量地址 vs 值传递,不是
defer特有,但defer加剧了这个陷阱
defer 和 return 谁先谁后?能改返回值吗?
return 语句执行分两步:先计算返回值并写入返回寄存器(或栈帧),再执行所有已注册的 defer,最后真正跳出去。这意味着 defer 可以读写命名返回值。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
使用场景:统一记录耗时、修改错误返回、补充日志上下文。
- 只有函数有**命名返回参数**(如
func foo() (err error)),defer才能修改它 - 匿名返回值(如
func() int)无法被defer修改 -
defer中 panic 不会跳过其他defer,但会中断后续普通语句;recover 必须在defer函数体内调用才有效
panic 时 defer 还执行吗?recover 放哪儿才管用?
会执行,而且全部执行完才真正 panic。但 recover 必须放在 defer 函数内部,并且该 defer 必须在 panic 发生**之前**注册,否则没机会运行。
常见错误现象:
把 defer recover() 写在 panic 后面,IDE 会标红提示 “Unreachable code”;或者 recover 写在普通函数里,完全不生效。
- 必须这样写:
defer func() { if r := recover(); r != nil { /* 处理 */ } }() -
panic("xxx")后面的defer不会被注册,直接跳过 - 嵌套函数中,外层
defer对内层panic依然有效,但 recover 只捕获当前 goroutine 的 panic
真正容易被忽略的是:defer 的注册时机和参数绑定是静态的,而执行时机是动态的——它既不是“马上”,也不是“随便什么时候”,而是在函数生命周期终点那一个精确的切面。写多了会下意识当成普通语句,一疏忽就掉坑里。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










