go 关键字 defer 使用详解
目录
go 关键字 defer 使用详解
简介
defer
是 Go 语言的一大特性,用 defer 可以来声明一些延迟函数,这些延迟函数会被放进队列里,在外层函数执行完成后会依次执行延迟函数:
- 在函数、方法返回 return 之前执行
- 可以同时设置多个 defer 函数,执行顺序遵循 FILO 先进后出 顺序
- defer 会将运行结果存在栈中,等到 return 之后再推出来执行
- 一般常用于资源清理、锁释放、文件资源关闭、关闭数据库连接、与 panic recover 结合使用等
一、场景一:基础使用
func main() {
defer fmt.Println(1) // 输出1
x = 2
fmt.Println(x)
return
}
2
1
二、场景二:先进后出
func main() {
defer fmt.Println(1) // 输出1
defer fmt.Println(2) // 输出1
x = 3
fmt.Println(x)
return
}
3
2
1
三、场景三:闭包使用
func main() {
fmt.Println("res:", testDefer()) // res:3
}
func testDefer() int {
var i = 1
defer func() { // 将函数存储在栈上,最后执行的时候调用该函数,打印出i,所以i的值在后面的改动生效
fmt.Println("defer2:", i) // i=3
}()
i++ // i=2
defer fmt.Println("defer3:", i) // 将结果“2” 存储在栈上,执行时输出
defer fmt.Println("defer4:", i+1) // 结果 3,但是不会影响 i 的值
i++ //i=3
return i // 可以看作 var rsp=i,return rsp,所以defer里改了i的值时没用的
}
结果: defer4: 3 defer3: 2 defer2: 3 res: 3
四、生产场景
- 打印耗时
func ProcessJob() {
start := time.Now()
defer func() {
fmt.Printf("耗时: %v", time.Since(start))
}()
// 复杂业务逻辑...
}
- 资源关闭
func ProcessFileFixed() {
f, _ := os.Open("data.log")
defer func(){
_=f.Close() // 确保资源释放
}
// 业务逻辑...
}
- 锁关闭
func ProcessJob() {
var mu=sync.Mutex
mu.Lock()
defer func(){
mu.Unlock() // 解锁,避免死锁
}
// 业务逻辑...
}
- 事务提交
func TransferMoney(db *sql.DB) error {
var err error
tx, err := db.Begin()
if err!=nil{
return err
}
defer func() {
if err!=nil{
tx.Rollback()
}else{
tx.Commit()
}
}()
// 业务逻辑...
return nil
}
- panic 捕获
func ProcessJob() {
start := time.Now()
defer func() {
if p := recover(); p != nil {
// 打印堆栈日志
}
}()
// 复杂业务逻辑...触发 panic
return
}