golang的defer
文章目录
- 把 defer 想象成"临时便签"
- 用生活例子理解:
- 更直观的对比:
- **没有 defer 的代码:**
- **有 defer 的代码:**
- 执行时机的详细说明:
- 关键理解点:
- 用计时器例子:
把 defer 想象成"临时便签"
当你写 defer
时,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 的代码:
func openFile() {file, _ := os.Open("test.txt")// 做一些操作...if 某个条件 {file.Close() // 要记得关闭文件return}// 做更多操作...if 另一个条件 {file.Close() // 又要记得关闭文件return}file.Close() // 还要记得关闭文件
}
有 defer 的代码:
func openFile() {file, _ := os.Open("test.txt")defer file.Close() // 一次性"预约"关闭操作// 做一些操作...if 某个条件 {return // 文件会自动关闭}// 做更多操作...if 另一个条件 {return // 文件会自动关闭}// 函数结束,文件会自动关闭
}
执行时机的详细说明:
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都会执行
用计时器例子:
func 做作业() {fmt.Println("开始做作业")defer fmt.Println("收拾桌子") // 便签:记住要收拾桌子fmt.Println("做数学题")fmt.Println("做语文题")// 函数结束时,自动执行:收拾桌子
}
这样理解了吗?defer
就像是在函数里贴便签,提醒自己在离开前要做什么事情!