defer 执行顺序
🟢 简单题目描述
以下代码的输出是什么?
func main() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println(0)
}期望输出
0
3
2
1进阶问题
以下代码的输出是什么?
func main() {
i := 0
defer fmt.Println(i)
i = 10
fmt.Println("hello")
}期望输出
hello
0提示
- defer 的执行顺序是 LIFO(后进先出)
- defer 的参数在声明时立即求值
解法一:理解 defer 执行顺序
参考答案 (2 个标签)
defer LIFO
核心概念
defer 语句的执行特点:
- 执行时机:函数返回前执行
- 执行顺序:LIFO(Last In First Out,后进先出)
- 参数求值:声明时立即求值(而非执行时)
图解
函数调用栈(defer 声明顺序):
┌─────────────┐
│ defer 1 │ 最后声明
├─────────────┤
│ defer 2 │
├─────────────┤
│ defer 3 │ 最先声明
└─────────────┘
执行顺序(defer 执行顺序):3 → 2 → 1代码示例
func example() {
defer fmt.Println(1) // 栈底
defer fmt.Println(2)
defer fmt.Println(3) // 栈顶
fmt.Println(0)
}
// 输出:
// 0 <- 普通语句先执行
// 3 <- defer 后执行,栈顶先出
// 2
// 1解法二:理解 defer 参数求值时机
参考答案 (2 个标签)
defer 参数求值
核心概念
defer 的参数在声明时立即求值,而不是执行时。
func example() {
i := 0
defer fmt.Println(i) // i = 0,立即求值
i = 10 // 修改 i 不影响 defer 的参数
}
// 输出:0如果想获取最新值
func example() {
i := 0
defer func() {
fmt.Println(i) // 闭包,获取最新值
}()
i = 10
}
// 输出:10defer 修改返回值
func example() (result int) {
defer func() {
result++ // 修改命名返回值
}()
return 0
}
// 返回值:1对比:值类型 vs 引用类型
func valueExample() {
i := 0
defer fmt.Println(i) // 输出 0(值类型)
i = 10
}
func referenceExample() {
m := map[string]int{"key": 0}
defer fmt.Println(m["key"]) // 输出 0(立即求值)
// defer 闭包获取最新值
defer func() {
fmt.Println(m["key"]) // 输出 10
}()
m["key"] = 10
}常见陷阱
陷阱 1:循环中的 defer
func main() {
for i := 0; i < 3; i++ {
defer fmt.Println(i)
}
}
// 输出:2, 1, 0
// 原因:LIFO,且 i 是值类型,每次循环 i 的值被捕获陷阱 2:defer 和 panic
func main() {
defer fmt.Println("defer 1")
panic("panic")
defer fmt.Println("defer 2") // 不会执行
}
// 输出:
// defer 1
// panic: panic陷阱 3:defer recover
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}()
panic("error")
}
// 输出:recovered: error