recover的概念
-
Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来
特点:
-
recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果
-
如果当前goroutine发生异常,调用recover可以捕获panic的输入值,且恢复正常的执行
Go语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,recover 的宕机恢复机制就对应其他语言中的 try/catch 机制。--->非常重要
panic和recover之间的关系
-
有 panic 没 recover,程序宕机。
-
有 panic 也有 recover,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
其他语言的异常处理机制的目的
以Java中的异常处理机制为例:
-
底层抛出异常,上层逻辑通过 try/catch 机制捕获异常
-
没有被捕获的严重异常会导致宕机,捕获的异常可以被忽略,让代码继续运行。
本质就是希望通过捕获异常的方式让程序继续运行下去
让程序在崩溃时继续运行示例
需求:
-
实现一个Run函数
-
传入一个匿名函数或闭包后的执行函数--->形参
-
-
传入函数以任何形式发生 panic 崩溃后,可以将崩溃发生的错误打印出来
-
同时允许后面的代码继续运行,不会造成整个进程的崩溃。
package main
import (
"fmt"
"runtime"
)
/*
定义一个结构体,里面的元素定义为抛出异常时需要传递的上下文信息
*/
type panicContent struct {
function string //当前所在函数
}
/*
声明描述错误的结构体,保存执行错误的函数。
*/
/*
实现一个run函数,形参为一个函数或者是闭包
*/
func Run(entry func()) {
//defer标记宕机处理
defer func() { //--->非常重要:defer 将闭包延迟执行,当 panic 触发崩溃时,Run() 函数将结束运行,此时 defer 后的闭包将会发生调用
//发生宕机时,获取panic传递的上下文并打印
err := recover() //recover() 获取到 panic 传入的参数
switch err.(type) { //错误类型断言
case runtime.Error:
//运行时异常
fmt.Println("runtime Error:", err)
default:
fmt.Println("another unknow Error:", err)
}
}()
entry()
}
func main() {
fmt.Println("运行前:")
//调用run函数,手动触发错误
Run(func() {
fmt.Println("手动触发宕机前:")
//使用panic结构体传递上下文--->一个指针对象,指向结构体
panic(&panicContent{ //--->这是将一个结构体附带信息传递给panic
"手动触发panic",
/*
使用 panic 手动触发一个错误,并将一个结构体附带信息传递过去
recover 就会获取到这个结构体信息,并打印出来
*/
})
fmt.Println("手动触发宕机后。")
})
/*
这不是一个运行时异常,宕机被恢复了,所以可以执行下面一个空指针错误的方法
*/
//手动触发空指针错误
Run(func() {
fmt.Println("赋值宕机前:")
var a *int
*a = 1