模块 3 · 第 5 课(共 5)课程中的15/50~12 min
模块课程(5/5)
`defer`:保证清理
defer 推迟调用的执行直到封闭函数
返回。即使函数因恐慌退出它也会运行。多个 defer
在同一函数中按后进先出顺序执行(后进先出)。
这是资源清理的惯用机制:关闭文件, 解锁互斥体、释放连接、恢复状态。
语法和规范用例
Go
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nil典型:f.Close()、mu.Unlock()、db.Close()、tx.Rollback()、
recover()。
立即评估论点,推迟执行
当您编写 defer foo(x) 时, x 会在
defer,不在执行时:
Go
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"后进先出顺序
延迟堆叠起来并从最近的开始执行:
Go
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1这与资源语义一致:最后打开的就是最先打开的 被关闭。
defer + recover:处理恐慌
defer 是拦截 panic 的唯一方法:
Go
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}陷阱:循环中的 defer
将 defer f.Close() 放入循环中会累积延迟 直到结束
函数,而不是每次迭代的函数。在一个长循环中,您打开了许多文件
并且仅在函数退出时关闭它们:文件描述符泄漏的风险。
Go
// MALE: defer accumulati
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // chiude TUTTI alla fine della funzione esterna
// ...
}
// MEGLIO: estrai in una funzione
for _, path := range paths {
elabora(path) // ogni chiamata ha il proprio scope di defer
}尝试一下
锻炼#go.m3.l5.e1
尝试:0加载中...
打印“inizio”,然后用 defer 推迟“fine”的打印,然后打印“mezzo”。输出必须是:inizio/mezzo/fine。
正在加载编辑器...
显示提示
当 main() 即将返回时,延迟运行。
3 次尝试后可用的解决方案
锻炼#go.m3.l5.e2
尝试:0加载中...
编写三个连续的延迟,在代码中按顺序打印 1、2 和 3。输出将为 3 / 2 / 1 (LIFO)。
正在加载编辑器...
显示提示
依次推迟三个;请记住它们以相反的顺序执行。
3 次尝试后可用的解决方案
Quiz#go.m3.l5.e3
准备好这打印什么? (注意:延迟参数立即计算)
Go
x := 10
defer fmt.Println(x)
x = 99回顾
defer call()推迟执行直到函数返回。- 多次延期 = LIFO 顺序。
- 立即评估参数,推迟执行。
- 用于确定性清理:文件、互斥体、连接。
defer+recover()拦截panic(罕见,在边界处)。- 切勿在长循环内使用
defer:它会累积直到外部函数返回。