When a recover() is no-op?

73 Views Asked by At

refer: https://go101.org/quizzes/panic-recover-1.html

package main

import "fmt"

func ExamplePanicGo101_1() {
    defer func() {
        fmt.Print(recover()) // catch panic(1)
    }()

    defer func() {
        defer fmt.Print(recover()) // catch panic(2)
        defer panic(1)
        recover() // no-op - B, should be called inside deferred function,
    }()

    defer recover() // no-op - A, should be called inside deferred function,
    panic(2)
    // Output:
    // 21
}

The test passes.

Questions:

  • I can understand no-op - A is no-op, since it's not called inside deferred function, but how no-op - B is no-op? Since it's called inside deferred function, I though it should catch the panic(2), but not.
1

There are 1 best solutions below

0
Brits On BEST ANSWER

I think you may have missed the following point re defer:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.

So when executing

defer fmt.Print(recover()) // catch panic(2)
defer panic(1)
recover() // no-op - B, should be called inside deferred function,

the steps are:

  • Evaluate recover() and, effectively, defer fmt.Print(2) (because recover() evaluates to 2).
  • defer panic(1)
  • recover() - noop as there is no active panic
  • execute deferred panic(1)
  • execute deferred fmt.Print(2) (remember that "Any functions deferred by F are then executed as usual")

The following example may help:

package main

import "fmt"

func main() {
    defer func() {
        fmt.Println(recover()) // catch panic(1)
    }()

    defer func() {
        fmt.Println("a")
        defer fmt.Println(fmt.Println("a1")) // The "a1" will print between a and b (note `3 nil` will be printed later, this is the return from the inner fmt.Println)
        defer fmt.Println(recover())         // catch panic(2)
        fmt.Println("b")
        defer panic(1)
        fmt.Println("c")
        recover() // no-op - B, should be called inside deferred function,
    }()

    defer recover() // no-op - A, should be called inside deferred function,
    panic(2)
    // Output:
    // a
    // a1
    // b
    // c
    // 2
    // 3 <nil>
    // 1
}