deferpanicrecovertry...catch...

几个要点注意

defer recovertry catchdefer recover
  • panic的返回值,通过recover函数来获取。 recover函数也是一个内置函数,专门用来接收panic函数返回值。当panic函数没有被调用或者没有返回值时,recover返回Nil.
    参考:《panic和recover的使用规则》
  • 执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
    参考:《Go语言宕机恢复(recover)——防止程序崩溃》
  • 虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。

流程分析

在这里插入图片描述

案例一:

package main
import "fmt"
func main() {  
	f()  
	fmt.Println("Returned normally from f.")  
}

func f() {  
	defer func() {  
		if r := recover(); r != nil {  
			fmt.Println("Recovered in f", r)  
		}
	}()
	fmt.Println("Calling g.")  
	g(0)  
	fmt.Println("Returned normally from g.")  
}

func g(i int) {  
	if i > 3 {  
		fmt.Println("Panicking!")  
		panic(fmt.Sprintf("%v", i))  
	}
	defer fmt.Println("Defer in g", i)  
	fmt.Println("Printing in g", i)  
	g(i + 1)  
}

代码输出结果:

Calling g.  
Printing in g 0  
Printing in g 1  
Printing in g 2  
Printing in g 3  
Panicking!  
Defer in g 3  
Defer in g 2  
Defer in g 1  
Defer in g 0  
Recovered in f 4  
Returned normally from f.  

案例二:

package main
import (
    "fmt"
    "runtime"
)
// 崩溃时需要传递的上下文信息
type panicContext struct {
    function string // 所在函数
}
// 保护方式允许一个函数
func ProtectRun(entry func()) {
    // 延迟处理的函数
    defer func() {
        // 发生宕机时,获取panic传递的上下文并打印
        err := recover()
        switch err.(type) {
        case runtime.Error: // 运行时错误
            fmt.Println("runtime error:", err)
        default: // 非运行时错误
            fmt.Println("error:", err)
        }
    }()
    entry()
}
func main() {
    fmt.Println("运行前")
    // 允许一段手动触发的错误
    ProtectRun(func() {
        fmt.Println("手动宕机前")
        // 使用panic传递上下文
        panic(&panicContext{
            "手动触发panic",
        })
        fmt.Println("手动宕机后")
    })
    // 故意造成空指针访问错误
    ProtectRun(func() {
        fmt.Println("赋值宕机前")
        var a *int
        *a = 1
        fmt.Println("赋值宕机后")
    })
    fmt.Println("运行后")
}

代码输出结果:

运行前
手动宕机前
error: &{手动触发panic}
赋值宕机前
runtime error: runtime error: invalid memory address or nil pointer dereference
运行后