I、panic
1、源码释义:
The panic built-in function stops normal execution of the current
goroutine. When a function F calls panic, normal execution of F stops
immediately. Any functions whose execution was deferred by F are run in
the usual way, and then F returns to its caller. To the caller G, the
invocation of F then behaves like a call to panic, terminating G's
execution and running any deferred functions. This continues until all
functions in the executing goroutine have stopped, in reverse order. At
that point, the program is terminated with a non-zero exit code. This
termination sequence is called panicking and can be controlled by the
built-in function recover.
翻译过来就是:
panic 内置函数停止当前 goroutine的正常执行。当函数 F 调用 panic 时,F 的正常执行会立即停止。F中的任何defer延迟调用的函数都以常规方式运行,然后 F 返回其调用方。对于调用方 G,F 的调用就像调用panic一样,终止 G 的执行并运行任何defer的函数。这一直持续到执行 goroutine 中的所有函数都以相反的顺序停止。此时,程序以非零退出代码终止。此终止序列称为 panicking ,可通过内置函数 recover 进行控制。
为了搞清楚defer,panic,和return执行的顺序,来看一个小例子:
2、例子
func main() {
A()
}
func A() {
defer func() {
fmt.Println("defer")
}()
fmt.Println("func A")
panic("panic in A")
return
}
输出:
func A
defer
panic: panic in A
goroutine 1 [running]:
main.A()
E:/go/basicGo/basictype/testpanic.go:15 +0x8b
main.main()
E:/go/basicGo/basictype/testpanic.go:6 +0x17
Process finished with the exit code 2
可以看出程序exit code2,没有正常运行,但是在panic前执行了defer函数,这就是源码释义中的:当函数 F 调用 panic 时,F 的正常执行会立即停止。F中的任何defer延迟调用的函数都以常规方式运行,然后 F 返回其调用方
如果是使用recover函数捕获异常:
func A() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recover:", r)
}
}()
fmt.Println("func A")
panic("panic in A")
return
}
输出:
func A
recover: panic in A
Process finished with the exit code 0
exit code 0 程序正常退出,说明panic被revover捕获,那recover(),又是个什么呢:
II、recover
1、源码释义:
The recover built-in function allows a program to manage behavior of a
panicking goroutine. Executing a call to recover inside a deferred
function (but not any function called by it) stops the panicking sequence
by restoring normal execution and retrieves the error value passed to the
call of panic. If recover is called outside the deferred function it will
not stop a panicking sequence. In this case, or when the goroutine is not
panicking, or if the argument supplied to panic was nil, recover returns
nil. Thus the return value from recover reports whether the goroutine is
panicking.
翻译:
内置函数recover 被用来管理 抛出panic的goroutine的行为,把recover()放在defer func(){}中调用,会恢复程序的正常执行,并停止panic序列,而且recover()会捕获panic中抛出的错误信息并且作为其返回值。如果在defer函数之外调用recover,它不会停止panicking 序列。另外,当 goroutine 没有发生panic,或者如果提供给panic的参数为 nil,则 recover 返回 nil。因此,可以通过recover的返回值是否为空来判断goroutine 是否崩溃
2、小例子:
func main() {
A()
}
func A() {
defer func() {
if r := recover(); r != nil {
fmt.Println("defer in func A catch the err:", r)
}
}()
B()
fmt.Println("This is func A")
}
func B() {
C()
fmt.Println("This is func B")
}
func C() {
fmt.Println("This is func C")
panic("panic err in func C")
}
输出:
This is func C
defer in func A catch the err: panic err in func C
This is func main
在这个例子中,A调用B,B调用C,可以看出在func C 中的panic最中在A中被捕获,pancking 在A中被stop,所以调用A的函数都能按照自己本来的方式运行,您也可以尝试在func B 或者func C中捕获panic的err。