底层逻辑

goroutine_panicpanic_panicdefer_panicpanicpanic

_panic结构体

go_panic
type _panic struct {
    argp      unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
    arg       interface{}    // argument to panic
    link      *_panic        // link to earlier panic
    pc        uintptr        // where to return to in runtime if this panic is bypassed
    sp        unsafe.Pointer // where to return to in runtime if this panic is bypassed
    recovered bool           // whether this panic is over
    aborted   bool           // the panic was aborted
    goexit    bool
}
pcspgoexitruntime.Goexitruntime.Goexitdeferpanicrecover

嵌套panic

接下来用个嵌套的panic例子来强化理解一下上面讲的

package main
func main() {
    defer func() {
        defer func() {
            panic("双重嵌套:panic")
        }()
        panic("panic1")
    }()
    defer func() {
        panic("panic2")
    }()
    panic("main-panic")
}

输出:

panic: main-panic
        panic: panic2
        panic: panic1
        panic: 双重嵌套:panic
goroutine 1 [running]:
main.main.func1.1()
        /home/zheng/STUDY/GoWork/demo/main.go:6 +0x39
panic(0x466460, 0x48a2b8)
        /usr/local/go/src/runtime/panic.go:965 +0x1b9
main.main.func1()
        /home/zheng/STUDY/GoWork/demo/main.go:8 +0x5b
panic(0x466460, 0x48a2c8)
        /usr/local/go/src/runtime/panic.go:965 +0x1b9
main.main.func2()
        /home/zheng/STUDY/GoWork/demo/main.go:11 +0x39
panic(0x466460, 0x48a298)
        /usr/local/go/src/runtime/panic.go:965 +0x1b9
main.main()
        /home/zheng/STUDY/GoWork/demo/main.go:13 +0x68

图解:

recovery

_panicrecoveredtruepanicpanicruntime.gorecover
func gorecover(argp uintptr) interface{} {
    gp := getg()
    p := gp._panic
    if p != nil && !p.recovered && argp == uintptr(p.argp) {
        p.recovered = true
        return p.arg
    }
    return nil
}
recoverydeferpanic