一、defer作用
Go语言的defer关键字提供了一种延迟执行机制,它能确保指定的函数调用在当前函数返回前被执行。这一特性常用于资源释放和异常处理场景。
二、defer基本特性
(1)执行时机:defer 语句会在外层函数返回前执行,无论函数是正常返回还是因 panic 而异常终止。
(2)执行顺序:多个 defer 语句按后进先出(LIFO)的顺序执行,类似于栈的操作方式。
(3)参数求值:defer 语句的参数在注册时就已完成求值,而非执行时才进行计算。
三、defer机制
1)参数绑定时机
在defer
语句中,参数值会在声明时立即确定。代码示例如下:
func main() {
a := 10
// 输出10
defer fmt.Println("defer a:", a)
a = 20
// 输出20
fmt.Println("current a:", a)
}
参数a
的值在defer
语句出现时就已经固定,运行结果如下:
2)执行顺序
执行顺序遵循后进先出(LIFO)原则,最后注册的defer语句将最先执行。代码示例如下:
func main() {
defer fmt.Println("first")
defer fmt.Println("second")
defer fmt.Println("third")
}
执行如果如下:
3)修改返回值
defer 语句能够修改具名返回值,但对匿名返回值无效。代码示例如下:
func main() {
defer fmt.Println(deferFuncReturn())
}
func deferFuncReturn() (result int) {
i := 1
defer func() { result++ }()
// 实际返回2
return i
}
执行如果如下:
四、应用场景
1)资源释放
确保正确释放文件、锁等资源。代码示例如下:
file, err := os.Open("test.txt")
if err != nil {
return err
}
defer file.Close()
2)锁管理
避免忘记解锁导致的死锁,代码示例如下:
mu.Lock()
defer mu.Unlock()
3)异常恢复
与recover配合捕获panic异常,代码示例如下:
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()
4)事务处理
确保数据库事务正确提交或回滚,代码示例如下:
tx, err := db.Begin()
defer func() {
if p := recover(); p != nil {
tx.Rollback()
}
}()
5)性能监控
记录函数执行时间,代码示例如下:
func doWork() {
start := time.Now()
defer func() {
fmt.Printf("耗时: %v\n", time.Since(start))
}()
}
五、defer使用注意事项
1)避免在循环中使用defer
,可能导致资源未及时释放。
2)对于高频调用的简单操作,建议手动释放资源而非使用defer
。
3)os.Exit()
等强制退出方式会跳过defer
的执行。
4)defer
中的错误容易被忽略,需要特别关注错误处理。