Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。
如下:
package mainimport "fmt"func main() {fmt.Println("start")defer fmt.Println(1)defer fmt.Println(2)defer fmt.Println(3)fmt.Println("end")}
输出结果如下:
startend321
由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。
defer执行机
在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
panic和recover
在函数部分介绍了几个内部函数,其中panic和revocer是Go语言中用来处理错误的。
比如:
package mainimport "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 +0x40main.main()E:/DEV/Go/src/code.rookieops.com/day02/defer/main.go:24 +0x85exit status 2
上面的例子程序执行到f2函数的panic的时候就触发错误直接退出了,后面的语句和f3函数没有继续执行。如果要继续执行后面的语句就需要使用recover函数,如下:
package mainimport "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之前定义
