在Go语言中,使用错误进行函数参数验证是一种好的模式吗?

huangapple go评论107阅读模式
英文:

Is function parameter validation using errors a good pattern in Go?

问题

参数验证使用错误返回代码被认为是一种良好的实践吗?我的意思是在哪些情况下应该使用错误而不是恐慌(是否有任何指南)。

例如:

  • 检查非nil值并在其为nil时返回错误,这是一种好的实践吗?
  • 或者检查正确的整数范围等。

我想象中,经常使用错误会让Go感觉非常像C语言,并且看起来很糟糕。在这些情况下,恐慌是一个好的选择吗?

或者,一个Gopher应该采用Python/Ruby/JS的方式,即"让它失败"?

我有点困惑,因为在我理解中,恐慌是真正的"错误"。但是始终使用错误只会让事情变得糟糕。

而且,即使我返回错误代码:如果有人向我的函数传递错误的参数但忽略错误代码,我能做什么?-> 什么都做不了!所以,老实说,在使用错误代码而不是恐慌的语言中,这并不是很清楚。

英文:

Is parameter validation using error return codes considered good practice ? I mean where should somebody use errors vs panics (are there any guidelines?).

For instance:

  • Is checking for non-nil + returning an error if it is nil a good
    practice ?
  • Or checking for correct integer ranges etc.

I imagine that using errors that often would make Go feel very C-ish and would look pretty bad. Are panics a good alternative in those situations ?

Or should a Gopher use the Python/Ruby/JS-approach "just let it fail" ?

I'm a bit confused because panics are for real "errors" in my understanding. But using errors all the time is just bad.

And even if I would return error code: What could I do if somebody passes wrong parameter to my function but ignores the errors codes ? -> Nothing! So honestly I would say panics are nice for those situations but in a language where error codes are used over panics this is not very clear.

答案1

得分: 28

在Go语言中,“逃逸”panic(我指的是由你的包的公共API组成的函数可能产生的)用于处理程序员的错误。因此,如果你的函数接收一个指向对象的指针,并且该指针不能为nil(比如,表示值缺失),那么就继续解引用该指针,如果它为nil,运行时会自动引发panic。如果一个函数期望一个必须在某个特定范围内的整数,如果不在该范围内就引发panic,因为在一个正确的程序中,所有可能传递给你的函数的值都在该范围内,如果不在该范围内,要么是程序员没有遵守API的规定,要么是他们没有对从外部获取的值进行清理,这不是你的错。

另一方面,像打开文件失败或执行其他操作失败这样的问题,当函数被正确调用时,不应该引发panic,而是应该返回适当的错误。

请注意,对于在.NET和Java代码的公共API函数中显式检查null参数的建议,其目标是使此类错误更易读。但由于99%的.NET和Java代码只是让所有异常传播到顶层(然后显示或记录),这只是用一个(由运行时生成的)异常替换另一个异常。它可能使错误更明显——执行在API函数中失败,而不是在调用堆栈的更深处失败——但会给这些API函数增加不必要的冗余代码。所以是的,这是有主观观点的,但我的主观观点是:在Go中让它崩溃是可以的——你会得到一个描述性的堆栈跟踪。

简而言之,

  • panic用于程序错误;
  • 返回错误用于函数执行预期任务时出现的问题。

关于运行时问题的处理,

  • panic用于程序错误;
  • 返回错误用于函数执行预期任务时出现的问题。

另外,panic的另一个合理用途是在深层递归处理/计算中快速返回“冷路径”;在这种情况下,应该捕获并处理panic,并且相应的公共API函数应该返回错误。详细信息请参见这个链接这个链接

英文:

"Escaping" panics<sup>1</sup> in Go (I mean, those which might be produced by the functions comprising the public API of your package) are to deal with errors programmers do. So, if your function gets a pointer to an object, and that can't be nil (say, to indicate that the value is missing) just go on and dereference the pointer to make the runtime panic itself if it happens to be nil. If a function expects an integer that must be in a certain range, panic if it's not in that range &mdash; because in a correct program all values which might be passed to your function are in that range, and if they don't then either the programmer failed to obey the API or they did not sanitize the value acquired from the outside which, again, is not your fault.

On the other hand, problems like failure to open a file or pefrorm some other action your function is supposed to perform when called correctly should not cause panics and the function should return an appropriate error instead.

Note that the recommendation for explicit checking for null parameters in the functions of public APIs in .NET and Java code has different goal of making such kinds of errors sort-of more readable. But since 99% of .NET and Java code just lets all the exceptions propagate to the top level (and then be displayed or may be logged) it's just replacing one (generated by runtime) exception with another. It might make errors more obvious&mdash;the execution fails in the API function, not somewhere deeper down the call stack&mdash;but adds unnecessary cruft to these API functions. So yes, this is opinionated but my subjective opinion is: to let it just crash is OK in Go&mdash;you'll get a descriptive stack trace.

TL;DR

With regard to processing of run-time problems,

  • panics are for programming errors;
  • returning errors is for problems with carrying out the intended tasks of functions.

<sup>1</sup> Another legitimate use for panics is quick "cold-path" returning from deep recursive processing/computation; in this case panic should be caught and processed by your package, and the corresponding public API functions should return errors. See this and this for more info.

答案2

得分: 2

这个问题的答案是主观的。以下是我的想法:

关于panic,我喜欢Go By Example(参考链接)中的这句话:

panic通常意味着出现了意外错误。我们通常使用它来快速失败处理在正常操作中不应该发生的错误,或者我们没有准备好优雅地处理的错误。

根据你的用例描述,我认为你应该引发错误并处理这些错误。我进一步认为,良好的实践是在使用的函数中检查错误状态,并且用户应该在文档中检查是否提供了错误状态。

如果我遇到一个来自你正在编写的函数的错误,并且我检查后发现无法恢复,我会使用panic来停止执行。

英文:

The answer to this is subjective. Here are my thoughts:

Regarding panic, I like this quote from Go By Example (ref)

> A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.

In the description of your use case, I would argue that you should raise an errors and handle the errors. I would further argue that it is good practice to check the error status when one is provided by the function you are using and that the user should check if one is provided in the documentation.

Panics I would use to stop the execution if I run across an error that is returned from the function you are writing that I check and don't have a way to recover from.

huangapple
  • 本文由 发表于 2014年4月4日 21:01:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/22863605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定