一文掌握Golang的panic和recover实战
作者:CodeJR
简述
我们都知道在Go语言中的异常处理是通过方法返回error,然后在调用方法处接收error并处理,这里的error通常是使用在业务异常的处理。
如果程序发生数组越界、空指针等异常就不会再通过error来处理,而是通过panic直接报错并终止程序和打印出堆栈信息。那么如何在程序发生panic的时候去处理这个异常而不是终止程序呢?这个时候就需要使用到recover,recover可以捕获到panic异常,并恢复程序的运行。
panic
- 调用panic后立即终止执行当前函数的剩余代码,在当前goroutine中执行当前函数所有的defer
- panic只会触发当前goroutine的defer
recover
- 调用recover可以捕获panic的异常,并恢复程序的执行
- recover只在defer延迟函数中调用才会生效
实战
示例1
我们首先在代码中直接使用recover捕获异常,并使用panic手动抛出一个异常,看看程序会怎么样
func main() { test() fmt.Println("main") } func test() { if err := recover(); err != nil { fmt.Println("recover: ", err) } panic("error") }
运行上面的代码之后可以从输出看到在test函数中发生了panic,并且直接终止运行,导致main函数中的打印也没有生效,这是因为在前面的时候有讲到过,recover必须在defer延迟函数中调用才会生效。
panic: error goroutine 1 [running]: main.test() C:/Users/lee/GolandProjects/test/main.go:33 +0x30 main.main() C:/Users/lee/GolandProjects/test/main.go:24 +0x13
示例2
修改上面的代码,将recover放到defer延迟函数中调用:
func main() { test() fmt.Println("main") } func test() { defer func() { if err := recover(); err != nil { fmt.Println("recover: ", err) } }() panic("error") }
这个时候我们再次运行代码,可以看到虽然在test函数中发生了panic,但是程序并没有终止运行,而是被defer中的recover捕获到了异常并恢复运行,同时main函数中的print也正常打印。
recover: error main
示例3
上面示例2中将recover是放到defer的函数中调用,那么如果在defer后面直接调用recover会生效吗?使用下面代码进行测试。
func main() { test() fmt.Println("main") } func test() { defer recover() panic("error") }
运行上面的代码之后发现在defer后面直接调用recover是无效的,程序照样会发生异常并终止运行,所以**recover必须是在defer的延迟函数中调用才会生效。**示例2中是匿名延迟函数,如果使用具名延迟函数同样有效。
panic: error goroutine 1 [running]: main.test() C:/Users/lee/GolandProjects/test/main.go:30 +0x58 main.main() C:/Users/lee/GolandProjects/test/main.go:24 +0x13
示例4
上面说到过recover必须在defer的延迟函数中调用,那下面的代码可以生效吗?
func main() { test() fmt.Println("main") } func test() { defer func() { defer recover() }() panic("error") }
运行上面的代码可以看到recover是生效的,recover函数被一个延迟函数调用,且recover函数本身作为一个延迟函数,这个情况下也是可以正常捕获panic异常的,程序运行如下:
main
到此这篇关于一文掌握Golang的panic和recover的文章就介绍到这了,更多相关Golang panic和recover内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!