文章目录
-
- [把 defer 想象成"临时便签"](#把 defer 想象成"临时便签")
- 用生活例子理解:
- 更直观的对比:
-
- [**没有 defer 的代码:**](#没有 defer 的代码:)
- [**有 defer 的代码:**](#有 defer 的代码:)
- 执行时机的详细说明:
- 关键理解点:
- 用计时器例子:
把 defer 想象成"临时便签"
当你写 defer
时,Go 会把这个函数调用写在一张"便签"上,等到当前函数结束时,再执行这些便签上的内容。
用生活例子理解:
go
func 回家() {
fmt.Println("1. 进门")
defer fmt.Println("4. 关灯") // 便签1:记住要关灯
defer fmt.Println("3. 锁门") // 便签2:记住要锁门
fmt.Println("2. 吃饭、看电视...")
// 函数结束时,Go会按照便签执行:
// 先执行便签2(锁门)
// 再执行便签1(关灯)
}
输出顺序:
1. 进门
2. 吃饭、看电视...
3. 锁门
4. 关灯
更直观的对比:
没有 defer 的代码:
go
func openFile() {
file, _ := os.Open("test.txt")
// 做一些操作...
if 某个条件 {
file.Close() // 要记得关闭文件
return
}
// 做更多操作...
if 另一个条件 {
file.Close() // 又要记得关闭文件
return
}
file.Close() // 还要记得关闭文件
}
有 defer 的代码:
go
func openFile() {
file, _ := os.Open("test.txt")
defer file.Close() // 一次性"预约"关闭操作
// 做一些操作...
if 某个条件 {
return // 文件会自动关闭
}
// 做更多操作...
if 另一个条件 {
return // 文件会自动关闭
}
// 函数结束,文件会自动关闭
}
执行时机的详细说明:
go
func example() {
fmt.Println("开始")
defer fmt.Println("我是defer 1")
defer fmt.Println("我是defer 2")
fmt.Println("中间")
if true {
fmt.Println("条件执行")
return // 函数在这里返回
}
fmt.Println("这行不会执行")
}
执行顺序:
fmt.Println("开始")
- 遇到
defer fmt.Println("我是defer 1")
→ 记在便签上 - 遇到
defer fmt.Println("我是defer 2")
→ 记在便签上 fmt.Println("中间")
fmt.Println("条件执行")
return
→ 函数要结束了,执行便签!- 执行便签2:
fmt.Println("我是defer 2")
- 执行便签1:
fmt.Println("我是defer 1")
输出:
开始
中间
条件执行
我是defer 2
我是defer 1
关键理解点:
- "包含它的函数" = 写
defer
的那个函数 - "返回之前" = 函数结束的那一刻,但还没有真正返回给调用者
- 无论怎么退出 = 正常return、panic、到达函数末尾,defer都会执行
用计时器例子:
go
func 做作业() {
fmt.Println("开始做作业")
defer fmt.Println("收拾桌子") // 便签:记住要收拾桌子
fmt.Println("做数学题")
fmt.Println("做语文题")
// 函数结束时,自动执行:收拾桌子
}
这样理解了吗?defer
就像是在函数里贴便签,提醒自己在离开前要做什么事情!