We can easily pass a function as a parameter and use it with defer
:
func main() {
test(rec)
}
func test(f func(int)) {
defer f(10)
panic("test")
}
func rec(v int) {
e := recover()
fmt.Println(e)
fmt.Println(v)
}
This works. Playground.
But what if we need to pass a method and then call recover
in that method?
type MyStruct struct {
Data string
}
func main() {
a := &MyStruct{}
test(a.Recover)
}
func test(f func(int)) {
defer f(10)
panic("test")
}
func (m *MyStruct) Recover(arg int) {
e := recover()
fmt.Println(e)
fmt.Println(arg)
}
Here we get some strange behavior, which I do not fully understand. Playground.
It seems like the method get called but recover
returns nil
and after that there is a (another?) panic. None of the golang docs and google results has helped me to understand the reason of such behavior. What am I missing?
The recover()
function returns nil when not called directly from the deferred function.
A call through the method value a.Recover
is not a direct call.
Use a wrapper function that calls recover and the method:
func main() {
a := &MyStruct{}
test(func(arg int) { a.Recover(arg, recover()) })
}
func test(f func(int)) {
defer f(10)
panic("test")
}
func (m *MyStruct) Recover(arg int, e interface{}) {
fmt.Println(e)
fmt.Println(arg)
}
Another option is to use a method expression, but this is probably straying from what you are trying to accomplish:
func main() {
a := &MyStruct{}
test(a, (*MyStruct).Recover)
}
func test(a *MyStruct, f func(*MyStruct, int)) {
defer f(a, 10)
panic("test")
}
func (m *MyStruct) Recover(arg int) {
e := recover()
fmt.Println(e)
fmt.Println(arg)
}