说明
本文介绍一下使用recover捕获panic的操作及遇到的一个坑。
使用recover捕获panic
正常情况下,发生panic的函数会导致程序异常退出,我们可以使用defer语句在另外一个函数中捕获到当前函数panic的error并做相应的逻辑处理:
package test1 import ( "fmt" "testing" ) func TestRecover(t *testing.T) { handleSth() } // 返回的函数 func sendResponse(err string) { // 有错误返回错误信息 if err != "" { fmt.Println("发生异常:", err) } else { println("成功sendResponse") } } // 专门用于捕获异常的 func rec1() { err := recover() // 注意这里捕获到的err是一个interface,需要与nil做比较 if err != nil { sendResponse(err.(string)) } else { sendResponse("") } } // 业务代码,可能发生异常 func handleSth() { // 如果函数中发生了异常会被rec1()函数捕获到 defer rec1() // 模拟业务代码中发生panic的情况 panic("发生了异常...") }
遇到的问题
正确的方式
正常情况下,我们使用下面的方式去捕获panic:
package test1 import ( "fmt" "testing" ) func rec1() { err := recover() if err != nil{ fmt.Println("err: ", err) } } func TestRecover(t *testing.T) { // 正确的捕获方式 defer rec1() panic("TestRecover raises error!") }
错误的方式
下面这种方式捕获不到panic:
package test1 import ( "fmt" "testing" ) func rec1() { err := recover() if err != nil{ fmt.Println("err: ", err) } } func TestRecover(t *testing.T) { // 错误的捕获方式 defer func(){ // 这里加一些其他的业务逻辑
rec1() }() panic("TestRecover raises error!") }
上面这种方法其实是想在recover到panic之前再做一些业务处理,结果没有捕获到想要捕获的panic会导致程序崩溃。
看了一下相关资料,解释应该是每一个recover应该“直接”与对应的panic配对,也就是说recover应该只能捕获到与其同一个作用域里的panic(具体原理还需要深入学习)。
像上面的那种写法应该在匿名函数中写panic才可以:
func TestRecover(t *testing.T) { // 错误的捕获方式 func(){ // 这里写一些其他的业务逻辑 defer rec1() panic("TestRecover raises error!") }() }
关于Golang中defer、panic与recover相关说明的参考:https://huoyingwhw.com/golangGuide/%E5%9F%BA%E7%A1%80/4/#82-defer