恐慌并从包裹中恢复

I'm trying to figure out how panic() and recover() works..

log package

package log

import (
    "fmt"
)

func Recover() {
    fmt.Println("Recovering!")
    if err := recover(); err != nil {
        fmt.Println("Error message recovered!")
    }
}

main package

package main

import (
    "fmt"
    log "www/pkg/log"
)

func main() {
    defer func() {
        log.Recover()
    }()

    panic("Fake error!")
}

output

Recovering!
panic: Fake error!

Why is Error message recovered! never printed?

The application must call recover directly from the deferred function to handle the panic.

The specification talks about the deferred function calling recover:

Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing. When the running of deferred functions reaches D, the return value of D's call to recover will be the value passed to the call of panic.

It's subtle, but it does not allow for an indirect call to recover. Also, the passage on the return value from recover mentions a direct call from the deferred function:

The return value of recover is nil if any of the following conditions holds:

  • recover was not called directly by a deferred function.

I was caught by this issue recently. Because the specification is very concise, it sometimes takes careful reading to pick up some points.

revocer only refers to the execution of the current goroutine: The docs say:

Executing a call to recover inside a deferred function **(but not any function called by it)** stops the panicking sequence by restoring normal execution

When you called another function, it did not panic, hence calling recover in the middle of it returns nil, and you do not catch the panic.