Skip to main content

Go func recover

你提到的理解误区在于 recover 的有效性。虽然 recover 是在 defer 语句中使用的,但它必须满足以下条件才能有效:

  1. recover 必须在一个 defer 调用的函数中直接执行。
  2. 这个 defer 调用的函数必须在 panic 发生后执行。

让我们更详细地解释为什么某些地方的 recover 无效。

代码分析

package main

import "fmt"

func test() {
defer func() {
fmt.Println(recover()) // 有效
}()
defer recover() // 无效!
defer fmt.Println(recover()) // 无效!
defer func() {
func() {
println("defer inner")
recover() // 无效!
}()
}()

panic("test panic")
}

func main() {
test()
}

详细解释

  1. 第一个 defer

    defer func() {
    fmt.Println(recover()) // 有效
    }()

    这个 defer 调用了一个匿名函数,并且在这个匿名函数内部直接调用了 recover。当 panic 发生后,这个 defer 会在函数返回之前执行,因此 recover 能够捕获到 panic

  2. 第二个 defer

    defer recover() // 无效!

    这里的 recover 不是在一个 defer 调用的函数中直接执行的,而是在 defer 语句中立即执行的。也就是说,recoverpanic 发生之前就已经执行了,所以无法捕获到 panic

  3. 第三个 defer

    defer fmt.Println(recover()) // 无效!

    类似于第二个 deferrecoverdefer 语句中立即执行,而不是在 defer 调用的函数中执行。因此,recoverpanic 发生之前就已经执行了,所以无法捕获到 panic

  4. 第四个 defer

    defer func() {
    func() {
    println("defer inner")
    recover() // 无效!
    }()
    }()

    在这个例子中,虽然 recover 是在 defer 调用的函数中执行的,但它是在嵌套的函数中执行的。只有在直接的 defer 调用的函数中,recover 才能捕获到 panic。嵌套的函数不能捕获到 panic

总结

  • 直接在 defer 调用的函数中执行的 recover 是有效的。例如:
    defer func() {
    fmt.Println(recover()) // 有效
    }()
  • defer 语句中立即执行的 recover 是无效的。例如:
    defer recover() // 无效!
    defer fmt.Println(recover()) // 无效!
  • 在嵌套函数中执行的 recover 是无效的。例如:
    defer func() {
    func() {
    println("defer inner")
    recover() // 无效!
    }()
    }()

希望这些解释能够帮助你理解为什么某些地方的 recover 无效。如果你还有其他问题或需要进一步的解释,请随时提问。