Golang 中的 panic 和 recover

panic

在 go 中,panic 的作用类似 java 中的 throw。

比如有一个函数 F 调用了 panic 方法,这个函数就停止运行了,然后执行 F 里的 defer 方法。如果这些 defer 里有处理 panic 的方法则进行处理然后返回到调用者,如果没有,在执行完所有 defer 方法之后,F 返回到其调用者。该调用者也如同触发了 panic 一样,按刚刚的逻辑执行。如果一直没有处理则一直向上传递,直至程序崩溃。

示例

package main

import "fmt"

func main() {
    fmt.Println("in main before call a")
    a()
    fmt.Println("in main after call a")
}

func a() {
    fmt.Println("in a before call b")
    b()
    fmt.Println("in a after call b")
}

func b() {
    fmt.Println("in b before call panic")
    panic(fmt.Sprintf("this is a panic"))
    fmt.Println("in b after call panic")
}

// output:
//
// in main before call a
// in a before call b
// in b before call panic
// panic: this is a panic
// 
// goroutine 1 [running]:
// panic(0x8b6c0, 0xc420074060)
//     /usr/local/go/src/runtime/panic.go:500 +0x1a1
// main.b()
//     /Users/Laily/mygo/test/main.go:17 +0x122
// main.a()
//     /Users/Laily/mygo/test/main.go:11 +0xa4
// main.main()
//     /Users/Laily/mygo/test/main.go:6 +0x14
// exit status 2

recover

recover 类似 java 中的 catch 功能,主要用来处理 panic 抛出的异常。注意,revocer 只能在 defer 的函数内使用。在正常的执行流程中,调用了 recover 方法仅仅会返回 nil 而不会有其他影响。如果当前协程抛出了 panic,调用 recover 则会捕获 panic 被调用时赋于的值,并且恢复程序的正常运行。

示例,在上面的 a 方法中加入 recover 处理:

package main

import "fmt"

func main() {
    fmt.Println("in main before call a")
    a()
    fmt.Println("in main after call a")
}

func a() {
    fmt.Println("in a before call b")
    defer func(){ //这里加入处理,注意 defer 一定要在可能引起 panic 的地方之前定义。否则 panic 产生了,但是 defer 还没有定义,就更别说捕获了。
        if r:= recover();r != nil{
            fmt.Println("in recover, get value= ",r)
        }
    }()
    b()
    fmt.Println("in a after call b")

}

func b() {
    fmt.Println("in b before call panic")
    panic(fmt.Sprintf("this is a panic"))
    fmt.Println("in b after call panic")
}

// output:
//
// in main before call a
// in a before call b
// in b before call panic
// in recover, get value=  this is a panic
// in main after call a

这里也可以看出,虽然在 a 方法中处理了 panic ,但是处理完后并没有继续执行 a 中的其他语句,而是返回到了上一级 main,mian 中才是可以正常执行后面语句的。