我现在正在学习go,我的一些代码看起来像这样:
a, err := doA()
if err != nil {
return nil, err
}
b, err := doB(a)
if err != nil {
return nil, err
}
c, err := doC(b)
if err != nil {
return nil, err
}
... and so on ...
这看起来有点不对,因为错误检查占用了大部分行。有没有更好的方法来处理错误?我可以通过一些重构来避免这种情况吗?
**更新:**谢谢你的回答。请注意,在我的例子中,doB依赖于a,doC依赖于b等等。因此,大多数建议的重构在这种情况下都不起作用。还有其他建议吗
6条答案
按热度按时间dwbf0jvd1#
这是一个常见的抱怨,有几个答案。
以下是一些常见的:
1 -没那么糟
这是对这些投诉的一种非常普遍的React。事实上,在代码中多几行代码并不是那么糟糕。这只是一个便宜的打字,非常容易处理时,在阅读方面。
2 -这其实是件好事
这是基于这样一个事实,即输入和阅读这些额外的行是一个非常好的提醒,事实上您的逻辑可能会在此时逃逸,并且您必须撤销在它之前的行中放置的任何资源管理。这通常与异常相比较,异常可以以隐式的方式中断逻辑流,迫使开发人员始终记住隐藏的错误路径。不久前,我写了一篇关于here的更深入的文章。
3 -使用panic/recover
在某些特定情况下,您可以通过使用已知类型的
panic
来避免一些工作,然后在您的包代码发布之前使用recover
,将其转换为适当的错误并返回该错误。这种技术最常用于展开递归逻辑,如(取消)封送拆收器。我个人尽量不滥用这一点,因为我与第1点和第2点的关系更密切。
4 -稍微整理一下代码
在某些情况下,您可以稍微重新组织逻辑以避免重复。
举一个简单的例子:
也可以组织为:
5 -使用命名结果
有些人使用命名结果从return语句中去掉err变量。但是我建议不要这样做,因为它节省的很少,降低了代码的清晰度,并且当在bail-out return语句之前定义一个或多个结果时,逻辑容易出现微妙的问题。
6 -使用if条件前的语句
正如Tom Wilde在下面的评论中所提醒的那样,
if
语句在Go语言的accept a simple statement中位于条件之前。所以你可以这样做:这是一个很好的Go习惯用法,经常使用。
在某些特定的情况下,我更倾向于避免以这种方式嵌入语句,只是为了使其独立于清晰的目的,但这是一个微妙和个人的事情。
daupos2t2#
您可以使用命名返回参数来缩短一些时间
Playground link
在你用Go编程一段时间后,你会意识到必须检查每个函数的错误,这会让你思考如果函数出错了到底意味着什么,以及你应该如何处理它。
ulydmbyx3#
2023年答案
现在你可以使用
errors
包中的helper来处理这些情况,比如errors.Join
:如果你想过滤掉你想单独处理的特定错误(而不是简单地将它们记录下来并进行一般的错误处理),你可以使用
errors.As
或errors.Is
:2013年的答案
如果你有很多这样的重复发生的情况,你有几个这样的错误检查,你可以定义自己的效用函数如下:
这使您可以选择其中一个错误,如果有一个非空的错误,则返回。
示例用法(full version on play):
当然,这只能在函数不相互依赖的情况下应用,但这是总结错误处理的一般前提条件。
p8h8hvxi4#
您可以创建具有结果值和错误的上下文类型。
krugob8w5#
可以将错误作为函数参数传递
我注意到“html/template”包中的一些方法可以做到这一点。
e3bfsja26#
在您看来,这是错误的,可能是因为您习惯于不在调用站点处理错误。这对于go来说是非常惯用的,但如果您不习惯的话,它看起来就像很多样板文件。
不过,它确实有一些优势。
1.您必须考虑在生成错误的站点处理此错误的正确方法。
1.很容易阅读代码,以查看代码将中止并提前返回的每个点。
如果它真的有bug,你可以用for循环和匿名函数来创造,但这通常会变得复杂和难以阅读。