Go语言流程控制:Defer
在 Golang 中,defer 是一个关键字,用于定义延迟执行函数。它可以将一个函数推迟到当前函数返回之后执行,即使该函数出现异常或错误也不会影响 defer 定义的代码块。
常见用例
以下是 defer 的一些常见用例: 1、关闭文件资源 使用 defer 关闭文件资源是一种非常常见的方法,可以确保无论代码中发生了什么,文件都能够被关闭。
f, err := os.Open("/path/to/file")
if err != nil {
log.Fatal(err)
}
defer f.Close()
2、记录耗时 我们可以在开始处理某个请求前调用 time.Now() 函数来记录起始时间,然后在退出函数时计算经过的时间并打印出来。
func processRequest(req *http.Request) {
start := time.Now()
defer logTime(start)
// 处理请求
}
func logTime(start time.Time) {
log.Printf("request took %v", time.Since(start))
}
3、锁的释放 当我们在使用互斥锁时,必须确保每次获取锁后都要及时释放锁,否则会导致死锁的情况。使用 defer 语句可以确保在任何情况下都会释放锁。
var mu sync.Mutex
func someFunc() {
mu.Lock()
defer mu.Unlock()
// 执行一些需要锁定的操作
}
注意事项
在使用 defer 时,需要注意以下几个问题:
- 延迟执行的函数参数会在定义时被计算,而不是在实际执行时计算。这意味着如果参数是一个指针或一个引用类型,并且在函数退出之前被修改了,那么这些修改会影响到延迟执行的函数。例如:
func someFunc() {
var a = 10
defer fmt.Println(a)
a = 20
}
// 输出结果为 10
- 如果有多个 defer 语句,它们的执行顺序与声明的顺序相反。也就是说,最后一个 defer 语句将首先执行,最先声明的 defer 语句将最后执行。
func someFunc() {
defer fmt.Println("first")
defer fmt.Println("second")
defer fmt.Println("third")
}
// 输出结果为 third, second, first
- 在函数中,return 语句并不是原子操作。具体来说,它分为两个步骤:第一步是将返回值赋给调用者;第二步是执行函数的清理工作(包括 defer 语句)。因此,在使用 defer 时,需要注意不要让 defer 影响函数的返回值。例如:
func someFunc() (result int) {
defer func() {
result++
}()
return 0
}
// 返回值为 1
- 如果在 defer 语句中使用了一个函数返回的错误值并且该函数可能会失败,则应该在调用函数后立即检查返回值。否则,在函数最后执行时,可能会忽略错误并导致不可预测的行为。例如:
func someFunc() (err error) {
file, err := os.Open("filename.txt")
if err != nil {
return err
}
defer func() {
if err := file.Close(); err != nil {
log.Fatal(err)
}
}()
// ...
}
🛒 站长推荐(京东联盟)
- 《Go 程序设计语言》(Go 语言圣经,机械工业出版社) —— Go 官方团队出品,公认入门第一书
- 《Go 语言实战》(异步图书,人民邮电出版社) —— 实战导向,面试前巩固工程手感
- 《Go 语言编程之旅:一起用 Go 做项目》(博文视点,电子工业出版社) —— 项目驱动入门,从零写出完整应用
- Keychron K1Max 矮轴机械键盘(Mac/Win 双系统,QMK/VIA 开源改键) —— 轻薄矮轴 + 开源固件,程序员桌面常客
- 罗技 MX Master 3S 无线鼠标(Flow 跨屏,静音电磁滚轮) —— 人体工学设计,写代码一整天手不酸
以上链接含京东联盟推广代码;通过链接购买本站可能获得少量佣金,不影响你的购买价格。
📮 关注公众号「GO语言入门之路」
每周更新 Go + AI 应用开发实战:AI 面试官完整项目、MCP、Agent 工程化,完整源码随文章首发。
微信扫码,或搜索「GO语言入门之路」关注,第一时间获取系列更新与源码,不再错过任何一篇。