为什么`推迟恢复()`不会引起恐慌?

jin*_*pan 14 go deferred-execution

为什么呼叫defer func() { recover() }()成功恢复恐慌goroutine,但呼叫defer recover()不?

作为一个简约的例子,这段代码并不恐慌

package main

func main() {
    defer func() { recover() }()
    panic("panic")
}
Run Code Online (Sandbox Code Playgroud)

但是,用恢复直接替换匿名函数恐慌

package main

func main() {
    defer recover()
    panic("panic")
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 10

引用内置函数的文档recover():

如果在延迟函数之外调用recover ,它将不会停止恐慌序列.

在你的第二种情况下,recover()本身就是延迟函数,显然 recover()不会调用自身.所以这不会阻止恐慌序列.

如果它recover()会调用recover()它,它会停止恐慌序列(但为什么会这样做?).

另一个有趣的例子:

以下代码也没有恐慌(在Go Playground上试试):

package main

func main() {
    var recover = func() { recover() }
    defer recover()
    panic("panic")
}
Run Code Online (Sandbox Code Playgroud)

这里发生的是我们创建一个recover函数类型的变量,它具有一个调用内置函数的匿名函数的值recover().我们指定将recover变量的值调用为延迟函数,因此recover()从中调用内置函数会停止panicing序列.


Von*_*onC 7

该处理恐慌部分提到,

两个内置功能,panic并recover协助报告和处理运行时恐慌

该recover功能允许程序管理恐慌goroutine的行为.

假设一个函数G 推迟一个函数D,该函数在正在执行的同一个goroutine中的函数中调用recover和panic发生G.

当延迟函数的运行到达时D,D调用的返回值recover将是传递给panic调用的值.
如果D正常返回,没有开始新的恐慌,恐慌序列就会停止.

这表明它recover意味着在延迟函数中调用,而不是直接调用.
当它发生混乱时,"延迟函数"不能是内置函数recover(),而是在延迟语句中指定的函数.

DeferStmt = "defer" Expression .
Run Code Online (Sandbox Code Playgroud)

表达式必须是函数或方法调用; 它不能括号.
对于表达式语句,内置函数的调用受到限制.

除特定的内置函数外,函数和方法调用和接收操作可以出现在语句上下文中.