9

是否可以“重新抛出”错误recover并保留原始堆栈跟踪?我所知道的最好的办法就是再次恐慌,但这确实会创建一个新的堆栈跟踪。

func do() {
    defer func() {
        cleanUp()
        if x := recover(); x != nil {
            handleError()
            panic(x)
        }
    }()
    doStuff()
}

我想要这个的动机是,除非我的函数正常退出或handleError运行,否则我的程序会死锁。除非我保留原始轨迹,否则我不知道它在哪里坠毁。

4

3 回答 3

12

解决方案是不调用recover,因为这样既不能重新抛出也不能访问堆栈跟踪。使用布尔标志而不是recover检查恐慌。

https://play.golang.org/p/PKeP9s-3tF

func do() {
    panicked := true
    defer func() {
        cleanUp()
        if panicked {
            handleError()
        }
    }()
    doStuff()
    panicked = false
}
于 2016-01-18T09:23:50.003 回答
6

堆栈中较高的延迟函数将在恐慌时运行,即使它们不调用recover().

只需删除 if 语句和重新恐慌。然后处理你的错误,让恐慌继续向上堆栈。

func do() {
    defer handleError()
    doStuff()
}

一个简单的演示:

https://play.golang.org/p/UiRou5MhUR

func a() {
    defer func() {
        fmt.Println("a")
    }()
    panic("test")
}
func b() {
    defer func() {
        fmt.Println("b")
    }()
}

func main() {
    fmt.Println("Hello, playground")
    b()
}

输出

Hello, playground
b
于 2016-01-17T20:11:12.247 回答
0

正如丹尼尔·康德·马林在这里提问的那样

我不相信你需要担心调用恐慌并传入一个恢复()的响应对象,创建一个神秘的或“新的”堆栈跟踪,至少在 go 1.17 中。看起来这样做只是向跟踪添加了另一个“src/runtime/panic.go:<linenum>”帧。

请参阅此示例测试: https ://goplay.space/#5i1RCJyiFJr

Go 不像其他语言对待 try/catch/throw/finally 那样对待恐慌。

于 2022-02-11T02:08:38.630 回答