defer关键字:延迟调用机制-《Go语言实战指南》
defer
是 Go 语言中用于延迟执行函数调用的关键字。它广泛用于资源释放、异常捕获、日志记录等场景,是构建健壮代码的利器。
一、基本语法
defer 函数调用
- •
defer
语句会推迟函数的执行,直到包含它的函数执行完毕。 - • 多个
defer
会以栈的方式后进先出(LIFO)执行。
示例:
func test() {defer fmt.Println("A")defer fmt.Println("B")fmt.Println("C")
}test()
// 输出:
// C
// B
// A
二、常见应用场景
1. 资源释放
file, err := os.Open("test.txt")
if err != nil {log.Fatal(err)
}
defer file.Close()
打开文件后,使用 defer
确保最终关闭文件,即使中途发生错误也能安全释放资源。
2. 锁的释放
mu.Lock()
defer mu.Unlock()
3. 捕获异常
结合 recover()
使用,优雅处理 panic:
func safe() {defer func() {if r := recover(); r != nil {fmt.Println("捕获异常:", r)}}()panic("something went wrong")
}safe()
// 输出:捕获异常: something went wrong
三、参数的求值时机
虽然函数调用被延迟,但参数会立即计算。
func test(x int) {defer fmt.Println("defer:", x)x++fmt.Println("normal:", x)
}test(10)
// 输出:
// normal: 11
// defer: 10
四、defer 的性能影响
- •
defer
虽然非常实用,但在高性能敏感代码中频繁使用 defer 可能造成微小开销。 - • Go 1.14 起,
defer
性能有显著优化。
五、多个 defer 的执行顺序
func f() {for i := 1; i <= 3; i++ {defer fmt.Println("defer", i)}
}
f()
// 输出:
// defer 3
// defer 2
// defer 1
六、小技巧:修改返回值
defer
可用于修改命名返回值,用于函数退出前调整返回数据。
func demo() (result int) {defer func() {result += 100}()return 1
}fmt.Println(demo()) // 输出 101
七、小结
特性 | 说明 |
延迟执行 | 在函数返回前执行,可用于清理资源 |
栈顺序 | 多个 defer 后进先出执行 |
参数时机 | 参数立即求值,函数调用延迟执行 |
常见用途 | 文件关闭、解锁、恢复 panic 等 |
返回值控制 | 可用于修改命名返回值 |
defer
简洁强大,是写出安全、可维护 Go 代码的重要利器。