I understand the following point wrt to recover()
behaviour in Go.
recover()
follows immediate evaluation but delayed execution.
So if it is not called inside a deferred function (code snippet 1), the recover()
is evaluated then and there itself at which point it is still nil
and hence our code panics.
If it is called inside a deferred function, the function call is registered but recover()
is called after the panic
has occurred and we recover successfully.
package main
import "fmt"
func main() {
defer recover() // since not called inside a deferred func, it will not recover successfully
panic("This is a panic")
}
Now keeping this in mind, I wrote the below code.
import (
"fmt"
)
func main() {
defer func(){
customRecover()
}()
panic("This is a panic")
}
func customRecover(){
if r:= recover(); r!= nil{
fmt.Println("Custom Recovery for: ",r)
}
}
I searched online for the reasoning and I get the same answer that
The return value of recover is nil if any of the following conditions holds:
- panic's argument was nil;
- the goroutine is not panicking;
- recover was not called directly by a deferred function.
But I'm failing to understand why the 2nd snippet is not working?!?
It satisfies all the 3 conditions strictly speaking. Is there a caveat that I'm missing? I guess the 3rd condition is not satisfied because it is not called directly but via a nested function call. But why does it need to be inside deferred only?
As you stated, the 3rd condition is not satisfied. Recover won't work in a nested function because panic
propagates through the call stack "downward" and in the 2nd snippet, the recover()
call in the customRecover
function is "upward" from the panic perspective, so it doesn't "see" the panic.