Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

如下:

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("start")
  5. defer fmt.Println(1)
  6. defer fmt.Println(2)
  7. defer fmt.Println(3)
  8. fmt.Println("end")
  9. }

输出结果如下:

  1. start
  2. end
  3. 3
  4. 2
  5. 1

由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。

defer执行机

在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:第九章 defer - 图1

panic和recover

在函数部分介绍了几个内部函数,其中panicrevocer是Go语言中用来处理错误的。

比如:

  1. package main
  2. import "fmt"
  3. func f1() {
  4. fmt.Println("f1 func...")
  5. }
  6. func f2() {
  7. var status bool
  8. // 关闭数据库
  9. func() {
  10. fmt.Println("关闭数据库失败")
  11. status = false
  12. }()
  13. if !status {
  14. panic("这里出现了严重的错误")
  15. }
  16. fmt.Println("f2 func...")
  17. }
  18. func f3() {
  19. fmt.Println("f3 func...")
  20. }
  21. func main() {
  22. f1()
  23. f2()
  24. f3()
  25. }

执行的结果如下:

  1. f1 func
  2. 关闭数据库失败
  3. panic: 这里出现了严重的错误
  4. goroutine 1 [running]:
  5. main.f2()
  6. E:/DEV/Go/src/code.rookieops.com/day02/defer/main.go:14 +0x40
  7. main.main()
  8. E:/DEV/Go/src/code.rookieops.com/day02/defer/main.go:24 +0x85
  9. exit status 2

上面的例子程序执行到f2函数的panic的时候就触发错误直接退出了,后面的语句和f3函数没有继续执行。如果要继续执行后面的语句就需要使用recover函数,如下:

  1. package main
  2. import "fmt"
  3. func f1() {
  4. fmt.Println("f1 func...")
  5. }
  6. func f2() {
  7. var status bool
  8. // 关闭数据库
  9. func() {
  10. fmt.Println("关闭数据库失败")
  11. status = false
  12. }()
  13. // 用revocer()恢复
  14. defer func() {
  15. err := recover()
  16. if err != nil {
  17. fmt.Println("恢复了,继续执行后面语句")
  18. }
  19. }()
  20. if !status {
  21. panic("这里出现了严重的错误")
  22. }
  23. fmt.Println("f2 func...")
  24. }
  25. func f3() {
  26. fmt.Println("f3 func...")
  27. }
  28. func main() {
  29. f1()
  30. f2()
  31. f3()
  32. }

其输出的结果如下:

  1. f1 func...
  2. 关闭数据库失败
  3. 恢复了,继续执行后面语句
  4. f3 func...

注意

  • recover必须和defer搭配使用
  • defer一定 要在可能引发panic之前定义