Panic和Recover

​ 本节将向您介绍第1章“Go和操作系统”中首次提到的技术。这种技术涉及使用panic()recover()函数,代码在panicRecover.go中,将分三部分进行讨论。

​ 严格来说,panic()是一个内置的Go函数,它终止Go程序的当前流程并开始panicking! 另一方面,recover()函数也是一个内置的Go函数,允许你收回那些使用了panic()函数的goroutine的控制权。

第一部分的程序如下:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func a() {
  6. fmt.Println("Inside a()")
  7. defer func() {
  8. if c := recover(); c != nil {
  9. fmt.Println("Recover inside a()!")
  10. }
  11. }()
  12. fmt.Println("About to call b()")
  13. b()
  14. fmt.Println("b() exited!")
  15. fmt.Println("Exiting a()")
  16. }

除了import语句块,这部分代码实现了一个函数a(),这个函数最重要的部分是defer代码块,它实现了一个匿名函数,当panic()函数被调用的时候,这个匿名函数就会被调用。

第二部分的代码:

  1. func b() {
  2. fmt.Println("Inside b()")
  3. panic("Panic in b()!")
  4. fmt.Println("Exiting b()")
  5. }

最后一部分代码解释了panic()recover()函数:

  1. func main() {
  2. a()
  3. fmt.Println("main() ended!")
  4. }

执行完整的代码,会得到如下的输出:

  1. $ go run panicRecover.go
  2. Inside a()
  3. About to call b()
  4. Inside b()
  5. Recover inside a()!
  6. main() ended!

这里发生的事真的令人印象深刻! 但是,正如您从输出中看到的那样,a函数没有正常结束,因为它的最后两个语句没有执行:

  1. fmt.Println("b() exited!")
  2. fmt.Println("Exiting a()")

然而,好消息是panicRecover.go根据我们的意愿结束而没有panicking,因为defer中使用的匿名函数控制了局面! 另请注意,函数b对函数a一无所知。 但是,函数a包含处理b函数的panic情况的Go代码!