I'm trying to figure out how panic()
and recover()
works..
package log
import (
"fmt"
)
func Recover() {
fmt.Println("Recovering!")
if err := recover(); err != nil {
fmt.Println("Error message recovered!")
}
}
package main
import (
"fmt"
log "www/pkg/log"
)
func main() {
defer func() {
log.Recover()
}()
panic("Fake error!")
}
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.