99 lines
1.7 KiB
Markdown
99 lines
1.7 KiB
Markdown
|
|
# 04-defer - defer机制
|
|||
|
|
|
|||
|
|
## 知识点讲解
|
|||
|
|
|
|||
|
|
### defer基本语法
|
|||
|
|
|
|||
|
|
`defer`语句会将函数调用推迟到当前函数返回之前执行。
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func example() {
|
|||
|
|
defer fmt.Println("最后执行")
|
|||
|
|
fmt.Println("先执行")
|
|||
|
|
}
|
|||
|
|
// 输出:
|
|||
|
|
// 先执行
|
|||
|
|
// 最后执行
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### defer的执行顺序
|
|||
|
|
|
|||
|
|
多个defer语句按照**后进先出(LIFO)**的顺序执行。
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func example() {
|
|||
|
|
defer fmt.Println(1)
|
|||
|
|
defer fmt.Println(2)
|
|||
|
|
defer fmt.Println(3)
|
|||
|
|
}
|
|||
|
|
// 输出:
|
|||
|
|
// 3
|
|||
|
|
// 2
|
|||
|
|
// 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### defer的参数求值
|
|||
|
|
|
|||
|
|
defer语句中的函数参数在defer声明时就被求值(立即求值),而不是在实际执行时。
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func example() {
|
|||
|
|
i := 0
|
|||
|
|
defer fmt.Println(i) // i=0 在此时被求值
|
|||
|
|
i = 10
|
|||
|
|
}
|
|||
|
|
// 输出: 0 (而不是10)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### defer修改返回值
|
|||
|
|
|
|||
|
|
使用具名返回值时,defer可以修改返回值。
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func example() (result int) {
|
|||
|
|
defer func() {
|
|||
|
|
result = 100 // 修改返回值
|
|||
|
|
}()
|
|||
|
|
return 50
|
|||
|
|
}
|
|||
|
|
// 返回: 100
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### defer的常见用途
|
|||
|
|
|
|||
|
|
1. **关闭资源**:
|
|||
|
|
```go
|
|||
|
|
file, err := os.Open("file.txt")
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
defer file.Close() // 确保文件被关闭
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **释放锁**:
|
|||
|
|
```go
|
|||
|
|
mutex.Lock()
|
|||
|
|
defer mutex.Unlock() // 确保锁被释放
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **恢复panic**:
|
|||
|
|
```go
|
|||
|
|
defer func() {
|
|||
|
|
if r := recover(); r != nil {
|
|||
|
|
fmt.Println("恢复:", r)
|
|||
|
|
}
|
|||
|
|
}()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 学习目标
|
|||
|
|
|
|||
|
|
完成本练习后,你将:
|
|||
|
|
- ✅ 理解defer的执行时机
|
|||
|
|
- ✅ 掌握defer的执行顺序(LIFO)
|
|||
|
|
- ✅ 了解defer参数的立即求值特性
|
|||
|
|
- ✅ 学会defer的常见应用场景
|
|||
|
|
|
|||
|
|
## 练习说明
|
|||
|
|
|
|||
|
|
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|