Go语言recover

Go语言recover教程

Go 语言 中,如果我们的 函数 或者程序出现了非常严重的问题,或者说我们的程序遇到了 panic 异常,此时我们的程序会终止运行。

但是,我们希望我们程序在发生错误后,我们能够做一些处理,保证程序可以继续运行,那么这时候,我们就需要使用异常恢复,即 recover。Golang 中的 recover 一般都是配套 defer 一起使用。

Go语言recover详解

语法

defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }()

说明

我们在 defer 中,使用 if 判断 ,如果程序出现了异常,那么我们使用 recover 尝试恢复,并且打印异常信息。

panic和recover使用原则

  • defer 需要放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。

  • recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。

  • 多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用

Go语言panic和recover的关系

如果有 panic 但没有 recover,那么程序会宕机。如果有 panic 也有 recover,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。

虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。在 panic 触发的 defer 函数内,可以继续调用 panic,进一步将错误外抛,直到程序整体崩溃。

案例

Go语言recover

panic 终止程序的运行,recover 捕获异常

package main import "fmt" func main() { fmt.Println("嗨客网(www.haicoder.net)") defer func() { if info := recover(); info != nil { fmt.Println("触发了宕机, Info =", info) } else { fmt.Println("程序正常退出") } }() fmt.Println("Hai") fmt.Println("Coder") panic("fatal error") fmt.Println("Over") }

程序运行后,控制台输出如下:

35_golang recover.png

我们在 main 函数里面,使用 defer 和 recover 捕获 panic 的异常,如果 info 不为空,那么就表明触发了异常,如果 info 为空,则未触发异常。

接下来,我们先输出 Hai,接着再次输出 Coder,接着使用 panic 触发异常,并设置异常信息,最后,在 recover 里面就可以捕获到异常,并输出异常信息。

Go语言recover

panic 终止程序的运行,recover 捕获异常

package main import ( "fmt" "time" ) func main() { fmt.Println("嗨客网(www.haicoder.net)") f() fmt.Println("end") } func f() { defer func() { fmt.Println("defer start") if err := recover(); err != nil { fmt.Println(err) } fmt.Println("defer end") }() for { fmt.Println("func begin") a := []string{"a", "b"} fmt.Println(a[3]) panic("bug") fmt.Println("func end") time.Sleep(1 * time.Second) } }

程序运行后,控制台输出如下:

36_golang recover.png

程序先执行 for 循环 循环里面的逻辑,因此先输出 func begin,接着我们定义了一个 string 类型数组,接着,我们越界访问该数组,此时会触发异常,我们的 recover 会捕获该异常,并输出异常信息。

Go语言recover总结

我们希望我们程序在发生错误后,我们能够做一些处理,保证程序可以继续运行,那么这时候,我们就需要使用异常恢复,即 recover。Golang 中的 recover 一般都是配套 defer 一起使用。Go 语言 recover 语法:

defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }()