延后执行(Defer)
defer 把一条语句注册成「离开当前块之前必须执行」的清理钩子。注册时不执行,执行时倒序。资源有 Dispose 协议的走 using,其余收尾场景走 defer。
基本形态
多个 defer 按声明的逆序执行,后注册的先跑:
defer { print("最先声明的 defer 最后跑"); }
defer { print("最后声明的 defer 先跑"); }
print("D");D
最后声明的 defer 先跑
最先声明的 defer 最后跑逆序保证「后开的先关」,与资源获取的嵌套顺序一致。
块作用域
defer 挂在它所在的块上,不是挂在整个函数上。内层块结束,内层的 defer 就执行:
print("A");
{
defer { print("内块 defer"); }
print("B");
}
print("C");A
B
内块 defer
C与返回值的关系
defer 定位是清理钩子,返回值表达式在 return 处求值,defer 对求值结果不可见:
func Expression() -> int
{
var n = 1;
defer { n = 99; }
return n + 0;
}n + 0 在 return 时已经算成 1,defer 再改 n 不影响它。
体内禁用语句
defer 体内不得使用 return、break、continue、fail,写了报 MS4027:
error MS4027: 'return' must not be used inside a defer body.清理钩子自己再跳转,执行顺序就没法推理了,语言层面直接禁止。
注意
defer 语句接单条语句,最常见写法是defer { 块 }。- 凡离开注册了 defer 的块都会触发:
return、fail(包括失败从被调函数传播穿过本帧)或块正常结束,defer 都在该块退出前跑。main 顶层带错退出前,main 里的 defer 同样先跑。唯一不跑的路径是进程级崩溃(crash),终态不执行任何清理。 - defer 注册在哪个块,就在那个块退出时跑:内块的 defer 不等函数退出。
- defer 里的 out 参数在 fail 路径不回写,失败路径的输出参数不可依赖。
最后更新于 2026年10月8日
