我应该使用恐慌还是返回错误?

时间:2017-06-12 16:27:56

标签: go error-handling panic

Go提供了两种处理错误的方法,但我不确定使用哪种错误。

假设我实现了一个经典的ForEach函数,它接受一个切片或一个映射作为参数。要检查是否传入了iterable,我可以这样做:

func ForEach(iterable interface{}, f interface{}) {
    if isNotIterable(iterable) {
        panic("Should pass in a slice or map!")
    }
}

func ForEach(iterable interface{}, f interface{}) error {
    if isNotIterable(iterable) {
        return fmt.Errorf("Should pass in a slice or map!")
    }
}

我看到一些讨论说panic()应该避免,但人们也说如果程序无法从错误中恢复,那么你应该panic()

我应该使用哪一个?选择正确的主要原则是什么?

8 个答案:

答案 0 :(得分:26)

来自Dave Cheney

  

panics对您的计划来说总是致命的。在惊慌中你永远不会假设   你的来电者可以解决问题。因此panic仅用于。{   特殊情况,在你不可能的情况下   代码或任何整合代码的人都可以继续。

对于整个程序,或者至少对于当前的goroutine,您应该假设恐慌将立即致命。问问自己“当这种情况发生时,应用程序是否会立即崩溃?”如果是,请使用恐慌;否则,请使用错误。

答案 1 :(得分:4)

使用panic

因为您的用例是滥用API 。如果程序正确调用了API,则永远不会在运行时发生这种情况。

实际上,如果删除了测试,则任何使用正确参数调用API的程序的行为都将与相同。该测试仅在早期失败,并显示一条错误消息,该错误消息对执行此错误的程序员有所帮助。理想情况下,在运行测试套件时,在开发过程中可能会出现一次恐慌,程序员甚至可以在提交错误代码之前就修复该调用,并且这种错误使用永远不会达到生产目的。

另请参阅this reponse来质疑使用错误验证函数参数是否是Go中的一种好模式?

答案 2 :(得分:1)

我喜欢在某些库中完成此操作的方式,这些库在常规方法DoSomething之上,其“ panicky”版本添加了MustDoSomething。我是go的新手,但我已经在多个地方看到过它,尤其是sqlx
通常,如果您想将代码公开给其他人,则应该拥有Must-和该方法的常规版本,或者您的方法/函数应该使客户端有机会恢复他们想要的方式,因此error应该以{{1​​}}惯用的方式提供给他们。
话虽如此,我同意,如果您的API /库使用不当,恐慌也可以。实际上,我还看到过go之类的方法,如果缺少关键的env.var,它们会惊慌。基本上是故障切换机制。

答案 3 :(得分:0)

恐慌通常意味着出乎意料的错误。主要用于在正常操作期间不应发生的错误快速失败,或者我们不准备优雅地处理。所以在这种情况下只返回错误,你不希望你的程序恐慌。

答案 4 :(得分:0)

如果在启动服务时没有提供某些强制性要求(例如数据库连接,需要一些服务配置),那么你应该使用恐慌。

任何用户响应或服务器端错误都应该返回错误。

答案 5 :(得分:0)

问自己以下问题:

  • 您是否期望发生这种特殊情况,而不管您对应用程序进行编码的程度如何?您认为让用户了解这种情况是您应用正常使用的一部分是否有用?将其作为错误处理,因为它与应用程序的正常运行有关。
  • 如果您进行适当的编码(并在某种程度上具有防御性),这种特殊情况是否不会发生? (例如:除以零,或超出范围访问数组元素)在该错误下,您的应用程序是否一无所知?恐慌。
  • 您是否拥有自己的API,并希望确保用户正确使用它?恐慌。如果使用不正确,您的API很少会恢复。

答案 6 :(得分:0)

我更喜欢使用紧急情况,这使得代码逻辑更易于编写和调试。请参阅下面的两个链接:

答案 7 :(得分:-2)

不要使用恐慌来进行正常的错误处理。使用错误和多个返回值。请参阅https://golang.org/doc/effective_go.html#errors