go语言学习笔记 — 基础 — 函数(12):防止程序崩溃—— 宕机恢复(recover)

Posted Locutus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言学习笔记 — 基础 — 函数(12):防止程序崩溃—— 宕机恢复(recover)相关的知识,希望对你有一定的参考价值。

无论是代码运行错误由Runtime层抛出的panic崩溃(如空指针访问,除数为0等情况),还是主动触发的panic崩溃,都可以使用defer和recover实现错误捕捉和恢复,使代码在崩溃后继续运行。

go语言没有异常系统,使用panic触发宕机类似其他语言的抛出异常,那么recover宕机恢复机制就对应try/catch捕获异常机制。


1. 让程序在崩溃时继续执行

下面代码实现函数保护作用,该函数传入一个匿名函数,当传入函数以任何形式发生panic崩溃时,可以把崩溃错误打印出来,同时允许代码继续执行,不会使整个进程崩溃。

package func_test

import (
	"fmt"
	"runtime"
	"testing"
)

// 声明描述错误的结构体,成员是保存错误的执行函数
type panicContext struct {
	function string
}

// 创建一个保护函数ProtectRun
func ProtectRun(entry func()) {
	defer func() { // 延迟处理函数
		err := recover() // 发生宕机时,recover()获取panic传入的上下文并打印。defer延迟调用闭包

		switch err.(type) { // 使用switch对变量err进行类型断言
		case runtime.Error: // 运行时错误
			fmt.Println("runtime error:", err)
		default: // 非运行时错误
			fmt.Println("error:", err)
		}
	}()

	entry() // 对入参函数进行调用,当发生panic时,先调用defer后的闭包,再退出
}

func TestProtect(t *testing.T) {
	fmt.Println("运行前")
	ProtectRun(func() {
		fmt.Println("手动宕机前")

		panic(&panicContext{ // 使用panic手动触发一个错误,并把一个结构体附带信息传入,被ProtectRun函数的recover()捕获
			"手动触发panic",
		})

		fmt.Println("手动宕机后") // panic之后的代码不再执行
	})

	ProtectRun(func() {
		fmt.Println("赋值宕机前")

		var a *int
		*a = 1 // 模拟代码中空指针赋值造成的错误,此时Runtime层抛出错误,被ProtectRun函数的reover()捕获

		fmt.Println("赋值宕机后") // panic之后的代码不再执行
	})

	fmt.Println("运行后")
}

2. panic和recover的关系

  • 有panic没recover,程序宕机
  • 有panic也有recover,程序不会宕机。执行完对应defer后,从宕机点退出当前函数,继续执行代码

以上是关于go语言学习笔记 — 基础 — 函数(12):防止程序崩溃—— 宕机恢复(recover)的主要内容,如果未能解决你的问题,请参考以下文章

go语言学习笔记 — 基础 — 函数:函数的返回值

go语言学习笔记 — 基础 — 函数:函数变量(把函数作为变量的值)

go语言学习笔记 — 基础 — 函数:函数调用

go语言学习笔记 — 基础 — 函数:可变参数

go语言学习笔记 — 基础 — 函数:闭包(closure)—— 引用了外部变量的匿名函数

go语言学习笔记 — 基础 — 高级数据类型 — 数据容器 — 数组:向函数传递数组