说明
本文介绍一下使用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相关说明的参考: