在 Go 语言 中,如果我们的 函数 或者程序出现了非常严重的问题,或者说我们的程序遇到了 panic 异常,此时我们的程序会终止运行。
但是,我们希望我们程序在发生错误后,我们能够做一些处理,保证程序可以继续运行,那么这时候,我们就需要使用异常恢复,即 recover。Golang 中的 recover 一般都是配套 defer 一起使用。
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
我们在 defer 中,使用 if 判断 ,如果程序出现了异常,那么我们使用 recover 尝试恢复,并且打印异常信息。
defer 需要放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。
recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。
多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
如果有 panic 但没有 recover,那么程序会宕机。如果有 panic 也有 recover,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。在 panic 触发的 defer 函数内,可以继续调用 panic,进一步将错误外抛,直到程序整体崩溃。
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")
}
程序运行后,控制台输出如下:
我们在 main 函数里面,使用 defer 和 recover 捕获 panic 的异常,如果 info 不为空,那么就表明触发了异常,如果 info 为空,则未触发异常。
接下来,我们先输出 Hai,接着再次输出 Coder,接着使用 panic 触发异常,并设置异常信息,最后,在 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)
}
}
程序运行后,控制台输出如下:
程序先执行 for 循环 循环里面的逻辑,因此先输出 func begin
,接着我们定义了一个 string 类型 的 数组,接着,我们越界访问该数组,此时会触发异常,我们的 recover 会捕获该异常,并输出异常信息。
我们希望我们程序在发生错误后,我们能够做一些处理,保证程序可以继续运行,那么这时候,我们就需要使用异常恢复,即 recover。Golang 中的 recover 一般都是配套 defer 一起使用。Go 语言 recover 语法:
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()