# go的defer关键字作用?
官方叫做:Defer statements延期声明 (opens new window)
# 核心作用与执行时机
- 延迟执行:
defer后面的函数调用不会立即执行,而是会被压入一个栈中,等外层函数执行完毕(正常返回或发生panic)前,再按后进先出(LIFO) 的顺序执行。 - 参数预计算:
defer语句中的参数(包括接收者)会在声明defer时就立即求值,而不是等到实际调用时才求值。
# 外层函数执行完毕是指?
“外层函数”就是包含 defer 语句的那个函数,也就是 defer 代码块所在的函数。
举个例子你就明白了
func outer() { // 这个就是“外层函数”
fmt.Println("开始")
defer fmt.Println("延迟执行") // defer 语句在 outer 函数内部
fmt.Println("结束")
// 此时 outer 函数即将返回
// 在返回之前,会执行上面 defer 的那个 "延迟执行"
}
func main() {
outer()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
执行顺序:
- 打印
"开始" - 遇到
defer,不立即执行,只是把fmt.Println("延迟执行")压入栈 - 打印
"结束" outer函数即将返回时,从栈中弹出defer内容,执行"延迟执行"
# 外层是什么意思?
- 相对于
defer语句本身:defer自己写在某个函数的“里面”,那么这个函数就是它的“外层”函数。 - 不是指
main函数,也不是指全局环境,就是指直接包裹defer的那个函数。
如果 defer 嵌套在多层函数调用中:
func level1() {
defer fmt.Println("level1 的 defer")
level2()
}
func level2() {
defer fmt.Println("level2 的 defer")
fmt.Println("level2 执行")
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
level2中的defer会在level2函数返回前执行。level1中的defer会在level1函数返回前执行。
总结一句话
defer 延迟执行的是它所在的函数的结尾处,而不是整个程序或其他函数的结尾。
# 核心要点总结
| 序号 | 要点 | 说明 |
|---|---|---|
| 1 | 执行时机 | defer 将函数调用推迟到外围函数返回之前执行(正常返回、执行到末尾或 panic 时都会触发)。 |
| 2 | 语法限制 | defer 后必须是函数或方法调用,不能加括号。内置函数的使用受常规表达式语句规则限制。 |
| 3 | 参数预求值 | defer 语句执行时,函数值和参数立即求值并保存,但函数本身不执行。 |
| 4 | 调用顺序 | 多个延迟函数按后进先出(LIFO) 的顺序执行(即最后一个 defer 最先执行)。 |
| 5 | 与 return 的关系 | 若外围函数有显式 return,延迟函数在结果参数被设置之后、函数返回调用者之前执行。 |
| 6 | nil 函数值 | 若延迟的函数值为 nil,则在调用该函数时(即返回前夕)发生 panic,而不是在 defer 语句处。 |
| 7 | 修改命名返回值 | 如果延迟函数是函数字面量,且外围函数有命名返回值,延迟函数可以访问并修改它们。 |
| 8 | 延迟函数的返回值 | 延迟函数自己的返回值会被丢弃,不影响外围函数的结果。 |
这段描述是 Go 语言规范中 defer 最权威的定义,所有 defer 的行为都严格遵循以上规则。
← go怎么定义模块? go日志记录解决方案 →