func sub(){ defer func (){ panic(2) }() panic(1) } func main(){ defer func(){ x:=recover() println(x.(int)); }() sub() }
我尝试了这段代码,似乎第一个恐慌 panic(1)
被第二个恐慌 panic(2)
“覆盖”。
但是这样做可以吗?或者调用可能会在 defer 函数内发生恐慌的 Golang 函数?
(在 C++ 中,从析构函数中抛出异常几乎是不可接受的。如果堆栈已经展开,它会终止程序。我想知道以类似方式发生恐慌在 Golang 中是否会很糟糕。)
是的,没关系。延迟函数引起的恐慌并不是真正的新的特殊状态,它只是意味着恐慌序列不会停止。
您的示例代码也证明了它没问题,甚至 panic()
称为可以通过对 recover()
的“上”级调用来停止延迟函数。
这里需要注意的一件事是,即使您在延迟函数中调用 panic()
,所有其他延迟函数仍然会运行。另外,来自延迟函数的没有 recover()
的 panic()
宁愿“包装”现有的恐慌,而不是“覆盖”它(尽管 recover()
调用确实只会返回传递给最后一次 panic()
调用)。
请参阅此示例:
func main() { defer func() { fmt.Println("Checkpoint 1") panic(1) }() defer func() { fmt.Println("Checkpoint 2") panic(2) }() panic(999) }
输出(在 Go Playground 上尝试一下):
c2e572c1c34a0369ef7989373914f540即使所有延迟函数都调用 panic()
,所有延迟函数都会执行,并且打印的最终恐慌序列包含传递给所有 panic()
调用的值。
如果您在延迟函数中调用 recover()
,您还会在最终打印输出中获得此“已恢复”状态或信息:
defer func() { recover() fmt.Println("Checkpoint 1") panic(1) }() defer func() { recover() fmt.Println("Checkpoint 2") panic(2) }()
输出(在 Go Playground 上尝试一下):
Checkpoint 2 Checkpoint 1 panic: 999 [recovered] panic: 2 [recovered] panic: 1 ...