9.8Go之函数之宕机恢复(recover)

9.8Go之函数之宕机恢复(recover)

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
/*
模拟代码中空指针赋值造成的错误
由 Runtime 层抛出错误,被 Run() 函数的 recover() 函数捕获到
*/

fmt.Println("赋值宕机后。")
})
/*
这是一个运行时异常
*/

fmt.Println("运行后。")
}

代码分析:

  • defer标记的函数--->panic触发崩溃run函数即将结束才会执行

  • panic--->可以将一个结构体传递给panic,通过指针传递,并且附带内容。panic获取到以后直接会打印里面的内容

  • 空指针错误被抛出会在run函数结束前由recover函数捕获到然后让程序继续往下执行--->不会退出

posted @ 2021-09-08 19:41  俊king  阅读(480)  评论(0)    收藏  举报