恢复恐慌后继续执行,而不知道哪个函数可能会出现恐慌

pig*_*fox 3 recover go panic

有人提到了这个问题:从恐慌中恢复的程序不会按预期退出 它工作正常,但它依赖于了解恐慌发生的位置才能放置延迟函数。我的代码如下。

package main

import "fmt"

func main() {
    defer recoverPanic()
    f1()
    f2()
    f3()
}

func f1() {
    fmt.Println("f1")
}

func f2() {
    defer f3() //<--- don't want to defer f3 here because I might not know f2 will panic, panic could occuer elsewhere
    fmt.Println("f2")
    panic("f2")
}

func f3() {
    fmt.Println("f3")
}

func recoverPanic() {
    if r := recover(); r != nil {
        fmt.Printf("Cause of panic ==>> %q\n", r)
    }
}
Run Code Online (Sandbox Code Playgroud)

在恐慌函数中延迟函数调用 f3() 是有效的,输出如下。

f1
f2
f3
Cause of panic ==>> "f2"
Run Code Online (Sandbox Code Playgroud)

如果您的应用程序不知道在哪里发生恐慌,我是否需要在每个可能发生恐慌的函数中延迟呢?注释掉defer f3()会给我以下输出。

f1
f2
Cause of panic ==>> "f2"
Run Code Online (Sandbox Code Playgroud)

f3 永远不会运行。

我的问题是如何继续执行程序而不在每个可能出现恐慌的函数中进行延迟函数调用?

Hym*_*sco 5

恐慌后您无法恢复函数执行。当当前执行行无法正确继续时,将使用 Panic 。在恐慌之后(如果可能的话)任意恢复执行会立即引发另一次恐慌,因为状态已经不正确,仅仅向前推进并不能解决这个问题。

例如,假设一个函数在尝试读取切片上的越界内容时发生恐慌。怎么能继续下去呢?继续下去意味着什么?它应该只读取越界内存位置并获取垃圾数据吗?继续使用零值吗?从切片中取不同的值?

您必须处理错误情况;通过显式恢复或预先检查/纠正会导致恐慌的条件。至少在标准库中,可能引发恐慌的函数会在其文档中如此说明,并解释哪些条件会导致恐慌。

如果您通常需要安全地调用void函数并从任何恐慌中恢复,您可以为此创建一个简单的包装函数。

func try(f func()) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("caught panic:", err)
        }
    }()
    f()
}
Run Code Online (Sandbox Code Playgroud)

然后

func main() {
    try(f1)
    try(f2)
    try(f3)
}
Run Code Online (Sandbox Code Playgroud)