Go语言中的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行。
如下:
package main
import "fmt"
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
输出结果如下:
start
end
3
2
1
由于defer
语句延迟调用的特性,所以defer
语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。
defer执行机
在Go语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
panic和recover
在函数部分介绍了几个内部函数,其中panic
和revocer
是Go语言中用来处理错误的。
比如:
package main
import "fmt"
func f1() {
fmt.Println("f1 func...")
}
func f2() {
var status bool
// 关闭数据库
func() {
fmt.Println("关闭数据库失败")
status = false
}()
if !status {
panic("这里出现了严重的错误")
}
fmt.Println("f2 func...")
}
func f3() {
fmt.Println("f3 func...")
}
func main() {
f1()
f2()
f3()
}
执行的结果如下:
f1 func
关闭数据库失败
panic: 这里出现了严重的错误
goroutine 1 [running]:
main.f2()
E:/DEV/Go/src/code.rookieops.com/day02/defer/main.go:14 +0x40
main.main()
E:/DEV/Go/src/code.rookieops.com/day02/defer/main.go:24 +0x85
exit status 2
上面的例子程序执行到f2
函数的panic
的时候就触发错误直接退出了,后面的语句和f3
函数没有继续执行。如果要继续执行后面的语句就需要使用recover
函数,如下:
package main
import "fmt"
func f1() {
fmt.Println("f1 func...")
}
func f2() {
var status bool
// 关闭数据库
func() {
fmt.Println("关闭数据库失败")
status = false
}()
// 用revocer()恢复
defer func() {
err := recover()
if err != nil {
fmt.Println("恢复了,继续执行后面语句")
}
}()
if !status {
panic("这里出现了严重的错误")
}
fmt.Println("f2 func...")
}
func f3() {
fmt.Println("f3 func...")
}
func main() {
f1()
f2()
f3()
}
其输出的结果如下:
f1 func...
关闭数据库失败
恢复了,继续执行后面语句
f3 func...
注意:
- recover必须和defer搭配使用
- defer一定 要在可能引发panic之前定义