go panic与recover分析及错误处理

时间:2022-06-05
本文章向大家介绍go panic与recover分析及错误处理,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

先介绍一下什么叫error 类型

error 是一种类型,表示错误状态的类型,如果没有错误则是nil。直白点将:error 类型就是描述错误的一种类型。

panic 在golang goroutine 的作用 panic 官方文档介绍:

panic 是用来停止当前程序的执行。当一个方法调用panic。 当函数F调用panic时,F的正常执行立即停止。 但是任何有F推迟的函数都会运行,意思是F定义有defer关键字声明的函数会执行,然后F返回给它的调用者。 对于调用者G来说,F的调用就像调用panic 一样,终止G的执行并运行任何延迟(带有defer 关键字)的函数。 这种情况会持续下去,直到正在执行的goroutine中的所有功能都以相反的顺序停止。 此时,程序终止并报告错误情况,包括panic的参数值。最后这种情况可以通过调用recover 来恢复函数的运行。 函数 recover 介绍

recover内置函数允许一段程序管理一个正在paincing goroutine的行为。

在defer 定义的函数(不是由它调用的任何函数)内部执行一段recover 函数,通过recover函数执行来停止panic 函数的执行,并且可以找出给panic所传递的错误值。 如果在defer 函数之外调用恢复,它不会停止panic的执行。 在这种情况下,或者当goroutine没有panicing时,或者提供给panicing的参数为零时,恢复返回nil。 因此,recover函数的返回值报告协程是否正在遭遇panicing 。

panic函数就是往外扔错误,一层接一层往上扔直到当前程序不能运行为止,不想让panic 函数扔的错误导致程序挂掉,就得使用recover 函数来接收panic 错误或者说是阻挡panicing ,并且recover 函数可以将错误转化为error 类型。因为panic 错误不会让defer 关键字定义的函数也停止运行,就是说defer 关键字声明的函数或者代码即使遇到错误也会执行。 一个函数里面有defer 关键字声明一个函数(假设叫catch 函数)和要运行出错的代码,在catch 函数里面调用recover 函数。recover 会拦截错误,不会让错误往上扔,返回给调用者error(里面有错误的信息)类型 ,从而使goroutine 不挂掉。 上代码:

package main


import (
    "fmt"
    "errors"
)

func main() {
    testError()
    afterErrorfunc()
}

func testError() {
    //defer catch()
    panic(" "panic 错误"")
    fmt.Println("抛出一个错误后继续执行代码")
}
func  catch()  {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)
        var err error
        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
        if err != nil {
            fmt.Println("recover后的错误:",err)
        }
    }
}

func afterErrorfunc(){
    fmt.Println("遇到错误之后 func ")
}

运行结果:

panic:  "panic 错误"

goroutine 1 [running]:
main.testError()
    E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:16 +0x40
main.main()
    E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:10 +0x27

Process finished with exit code 2

当panic 函数执行的时候导致后面函数 afterErrorfunc() 不能执行,main函数也抛出一个错误,整个程序异常退出。 通过defer 关键字调用 catch函数。

func testError() {
    defer catch()
    panic(" "panic 错误"")
    fmt.Println("抛出一个错误后继续执行代码")
}

程序运行结果:

testError() 遇到错误:  "panic 错误"
recover后的错误:  "panic 错误"
遇到错误之后 func 
Process finished with exit code 0

分析:程序正常结束,没有因为panic(错误)而到导致程序终止挂掉。错误被recover 函数接收,转化为error类型的错误,最后输出“ recover后的错误: “panic 错误” ” 而且后面 afterErrorfunc()执行。

一般在写的时候这么写 不用定义catch 函数:

func main() {
    testError()
    afterErrorfunc()
}

func testError() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
        }
    }()

    panic(" "panic 错误"")
    fmt.Println("抛出一个错误后继续执行代码")
}
func catch(err error) {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)

        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
    }
}

func afterErrorfunc() {
    fmt.Println("遇到错误之后 func ")
}

在发生panic 函数里面加入下述代码就可以拦截panicing, 并且不让程序挂掉和显示错误信息。

defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
        }
    }()

最后如果想将错误信息返回给调用者可以这么做:

func main() {
    err := testError()
    if err != nil {
        fmt.Println("main 函数得到错误类型:", err)
    }
    afterErrorfunc()
}

func testError() (err error) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
            switch x := r.(type) {
            case string:
                err = errors.New(x)
            case error:
                err = x
            default:
                err = errors.New("")
            }
        }
    }()
    panic(" "panic 错误"")
    fmt.Println("抛出一个错误后继续执行代码")
    return nil
}

func catch(err error) {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)
        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
    }
}

func afterErrorfunc() {
    fmt.Println("遇到错误之后 func ")
}

提前声明一个error 类型的变量。把错误信息传递给error变量,再把error变量返回给调用者。