美文网首页
Golang语法系列——recover异常处理

Golang语法系列——recover异常处理

作者: bkduck | 来源:发表于2021-09-29 20:22 被阅读0次

    现象

    • panic 只会触发当前 Goroutine 的 defer
    • recover 只有在 defer 中调用才会生效;
    • panic 允许在 defer 中嵌套多次调用;

    跨协程失效

    panic 只会触发当前 Goroutine 的延迟函数调用

    func main() {
        defer println("in main")
        go func() {
            defer println("in goroutine")
            panic("")
        }()
    
        time.Sleep(1 * time.Second)
    }
    
    $ go run main.go
    in goroutine
    panic:
    ...
    

    当我们运行这段代码时会发现 main 函数中的 defer 语句并没有执行,执行的只有当前 Goroutine 中的 defer

    失效的崩溃恢复

    在主程序中调用 recover 试图中止程序的崩溃,但是从运行的结果中我们也能看出,下面的程序没有正常退出。

    func main() {
        defer fmt.Println("in main")
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    
        panic("unknown err")
    }
    
    $ go run main.go
    in main
    panic: unknown err
    
    goroutine 1 [running]:
    main.main()
        ...
    exit status 2
    

    recover 只有在发生 panic 之后调用才会生效。然而在上面的控制流中,recover 是在 panic 之前调用的,并不满足生效的条件,所以我们需要在 defer 中使用 recover 关键字

    嵌套崩溃

    func main() {
        defer func(){
            fmt.Println("5")
            fmt.Println("in main")
        }()
        defer func() {
            fmt.Println("2")
            defer func() {
                fmt.Println("4")
                panic("panic again and again and again")
            }()
            defer func() {
                fmt.Println("3")
                panic("panic again and again")
            }()
            panic("panic again")
        }()
        fmt.Println("1")
        panic("panic once") 
    }
    
    >>>
    1
    2
    4
    5
    6
    in main
    
    panic: panic once
        panic: panic again
        panic: panic again and again
        panic: panic again and again and again
    exit status 2
    

    panic 先执行同级defer,然后同级defer按FILO顺序执行,若defer内部嵌套defer, 其执行顺序按内部嵌套FILO顺序执行。同时注意panic位置在defer 前面则同级后面defer不会执行

    panic()和recover()和defer运用

    • 程序panic,defer中使用recover恢复
    #执行panic,这时recover就不等于nil,然后程序先执行defer,然后panic终止
    #类似于try catch
    package main
    
    import (
        "log"
    )
    
    func protect(g func()) {
        defer func() {
            log.Println("done")
            // Println executes normally even if there is a panic
            if err := recover(); err != nil {
                log.Printf("run time panic: %v", err)
            }
        }()
        log.Println("start")
        g() //   possible runtime-error
    }
    func main() {
        protect(func() {
            log.Println("in g()")
            panic("dropout g()")
        })
    }
    
    输出
    2018/07/25 18:21:23 start
    2018/07/25 18:21:23 in g()
    2018/07/25 18:21:23 done
    2018/07/25 18:21:23 run time panic: dropout g()
    
    

    相关文章

      网友评论

          本文标题:Golang语法系列——recover异常处理

          本文链接:https://www.haomeiwen.com/subject/omzjnltx.html