本节将向您介绍第1章“Go和操作系统”中首次提到的技术。这种技术涉及使用panic()
和recover()
函数,代码在panicRecover.go
中,将分三部分进行讨论。
严格来说,panic()
是一个内置的Go函数,它终止Go程序的当前流程并开始panicking
! 另一方面,recover()
函数也是一个内置的Go函数,允许你收回那些使用了panic()
函数的goroutine
的控制权。
第一部分的程序如下:
package main import ( "fmt" ) func a() { fmt.Println("Inside a()") defer func() { if c := recover(); c != nil { fmt.Println("Recover inside a()!") } }() fmt.Println("About to call b()") b() fmt.Println("b() exited!") fmt.Println("Exiting a()") }
除了import语句块,这部分代码实现了一个函数a()
,这个函数最重要的部分是defer
代码块,它实现了一个匿名函数,当panic()
函数被调用的时候,这个匿名函数就会被调用。
第二部分的代码:
func b() { fmt.Println("Inside b()") panic("Panic in b()!") fmt.Println("Exiting b()") }
最后一部分代码解释了panic()
和recover()
函数:
func main() { a() fmt.Println("main() ended!") }
执行完整的代码,会得到如下的输出:
$ go run panicRecover.go Inside a() About to call b() Inside b() Recover inside a()! main() ended!
这里发生的事真的令人印象深刻! 但是,正如您从输出中看到的那样,a
函数没有正常结束,因为它的最后两个语句没有执行:
fmt.Println("b() exited!") fmt.Println("Exiting a()")
然而,好消息是panicRecover.go
根据我们的意愿结束而没有panicking
,因为defer
中使用的匿名函数控制了局面! 另请注意,函数b
对函数a
一无所知。 但是,函数a
包含处理b
函数的panic情况的Go代码!