传递要与defer一起使用的方法作为参数

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)
}