defer(关键字)
它是做什么的
defer 用于注册“延迟执行”的函数调用。
这些调用会在当前函数即将返回前执行,常用于资源清理(如关闭文件、解锁、释放连接)。
语法/规则
defer语句会先登记,等函数返回前再执行。- 一个函数内有多个
defer时,执行顺序是后进先出(LIFO)。 defer调用中的参数在“登记 defer 的那一刻”就会求值。defer常与return、错误处理一起使用,保证清理逻辑稳定执行。
多个 defer 执行顺序示例
| |
输出结果:
| |
从栈角度理解 defer
理解这个示例的关键是:
每个函数调用帧都有自己的 defer 栈,互不干扰。
谁先返回,就先清空谁自己的 defer 栈(后进先出)。
为了便于观察,下面把栈都写成“栈顶 -> 栈底”。
逐行 + 栈变化(核心示例)
| |
步骤拆解如下(栈写法:栈顶 -> 栈底):
进入
main,执行defer fmt.Println("defer4")。
main 栈:[defer4]
Func 栈:[]
当前输出:无调用
Func(),进入Func后执行defer fmt.Println("defer2")。
main 栈:[defer4]
Func 栈:[defer2]
当前输出:无执行
fmt.Println("func")。
main 栈:[defer4]
Func 栈:[defer2]
当前输出:func执行
defer fmt.Println("defer1")。
main 栈:[defer4]
Func 栈:[defer1, defer2]
当前输出:funcFunc返回,开始弹出Func的 defer 栈(后进先出)。
先执行defer1,再执行defer2。
main 栈:[defer4]
Func 栈:[]
当前输出:func -> defer1 -> defer2回到
main,执行defer fmt.Println("defer3")。
main 栈:[defer3, defer4]
Func 栈:[]
当前输出:func -> defer1 -> defer2main返回,开始弹出main的 defer 栈(后进先出)。
先执行defer3,再执行defer4。
main 栈:[]
Func 栈:[]
当前输出:func -> defer1 -> defer2 -> defer3 -> defer4
最终输出就是:
| |
你可以记一句话:defer 语句只是入栈,函数返回时才出栈执行;同一函数内严格后进先出。
参数求值时机示例
| |
输出结果:
| |
参数求值流程分解
defer fmt.Println("defer value:", value) 里的 value,在声明 defer 那一刻就被确定为 1。
所以后面即使把 value 改成 2,延迟调用里仍然打印的是当时保存的值。
用“栈”来理解就是:defer 入栈时,调用参数已经打包好放进栈节点里了,不会等到出栈时再重新取最新变量值。
常见错误
- 误以为多个
defer按书写顺序执行,实际是后写先执行。 - 误以为
defer参数在函数结束时才求值,实际在声明时就求值。 - 在循环里大量使用
defer却不关注性能和释放时机,可能造成资源堆积。 - 把不同函数作用域的 defer 执行顺序混在一起判断,导致输出顺序理解错误。