Rust的panic恢复哲学是什么?


Rust书中说,当程序出现意外报错panic时,将没有办法恢复,并建议优先使用Result作为返回值,而不是返回panic。

虽然std库提供了catch_unwind来允许程序在panic时继续执行,但文档中同样提到这个方法不应该被用于类似try/catch的模式。

Go也有panic的概念,但它有一个方便的recover方法来从panic中恢复。
一个有用的恢复案例是,如果你正在编写一个Web服务器框架,让用户传递自定义处理函数,你可以从框架中的自定义处理程序中恢复任何panic,这样服务器程序就不会因此而退出。

我应该在Rust中使用catch_unwind来实现这个目的吗?
还是说Rust有更好的替代方案或不同的理念来满足此类需求?

Reddit网友回复:
1、在Rust的生态系统中,panic通常是为不可恢复的错误保留的。一般来说,你应该尊重这一惯例,对绝大多数错误使用Result。

也就是说,在处理处理程序和回调之类的问题时,处理程序本身遇到无法恢复的错误是很常见的,但服务器进程可以通过忽略 panic 并继续进行处理程序的调用而恢复。这种情况就是catch_unwind存在的原因。如果你需要你的服务器在处理程序panic的情况下继续运行,请使用catch_unwind。

但是要有判断力。panic是一种钝器,相当于GOTO语句。你的处理程序对于正常的、可恢复的错误不应该panic,你的服务器应该围绕Result作为主要的错误处理机制来设计。

好的工程需要使用正确的工具,而catch_unwind很少是正确的工具。

2、注意:
panic总是在调用栈中向上传播,所以它们是一种结构化的代码流工具。不像goto,它允许从任何地方跳到当前函数中的任何地方。
panic会在任何超出范围的自有对象上运行drop(),提供适当的清理和释放资源的机会。

3、当涉及到panic时,rust和go都有相同的想法。它们应该用于不可恢复的错误和逻辑问题,而result/errors 用于正常的错误处理。它们都提供了一种从panic中恢复的方法,但一般来说你不应该这样做。
有些情况下,比如在webservers中,你宁愿让应用程序继续运行以完成其他请求,但你不应该依赖它来处理正常的错误。

4、如果你想让你的web服务器对不完美的自定义用户逻辑保持健壮,那么你肯定应该使用`catch_unwind'。

你肯定还应该记住其他答案中提到的catch_unwind的其他缺点。

你应该记住,在这种情况下,健壮性与快速失败原则背道而驰(失败越快越好,越大声越好)。也许在调试版本中禁用它,而在发布版本中适当地记录故障。

然而,健壮性绝对是一个合理的关注点--我听说它对Web服务器来说比平时更重要。

尽管panic是针对可恢复的错误的原则是好的,但简单地将一个数组索引到界外就会panic恐慌了。这有可能发生在每一个地方。

我说,如果这是你认为最好的,就使用它,不要让reddit吓唬你,让你盲目地遵循原则。