【问题标题】:Fail vs. raise in Ruby : Should we really believe the style guide?Ruby 中的 Fail vs. raise:我们真的应该相信风格指南吗?
【发布时间】:2015-11-03 10:25:31
【问题描述】:

Ruby 提供了两种以编程方式引发异常的可能性:raisefail,它们都是 Kernel 方法。根据文件,它们是绝对等价的。

出于习惯,我目前只使用raise。现在我找到了一些建议(例如here),使用raise 捕获异常,使用fail 处理不应该处理的严重错误。

但这真的有意义吗?当您编写一个类或模块并导致内部深处出现问题时,您通过fail 发出信号,您正在审查代码的编程同事可能会很高兴地理解您的意图,但使用的人em> 我的代码很可能不会查看我的代码并且无法知道异常是由raise 还是由fail 引起的。因此,我对raisefail的谨慎使用对他的决定没有任何影响,无论她是否应该处理。

有人能看出我的论点有缺陷吗?还是有其他标准,我可能想使用fail 而不是raise

【问题讨论】:

  • 我认为这个问题可以被视为题外话,因为它不包含特定问题,所以我认为它更适合例如Programmers
  • @m.cekiera 在引用其他网站时,指出cross-posting is frowned upon 通常会有所帮助
  • @m.cekiera:实际上,问题源于一个特定的问题(我正在编写一个库并想引发异常,当传递给方法的参数超出范围时),但我认为提供此信息无助于回答问题。不过感谢您的评论。

标签: ruby exception coding-style conventions


【解决方案1】:

使用“raise”捕获异常,使用“fail”捕获不应该处理的严重错误

这不是official style guide 或您提供的链接就此事所说的。

这里的意思是只在rescue 块中使用raise。也就是当你想说某事失败时使用fail,当重新抛出异常时使用raise

至于 “重要吗” 部分 - 它不是最严格遵守的规则之一,但您可以为任何约定提出相同的论点。你应该按照这个顺序:

  1. 您的项目风格指南
  2. 您的公司风格指南
  3. 社区风格指南

理想情况下,三者应该相同。


更新:从this PR(2015 年 12 月)开始,惯例是始终使用 raise

【讨论】:

  • 感谢您澄清这一点!这让我很清楚(尽管我仍然对这条规则的有用性感到有些困惑,因为我通常可以从代码中很容易地看出我是否重新抛出异常。据我所知,没有任何收获通过使用不同的命令来额外强调这一事实。
  • @user1934428,它只是正确名称的正确名称。此外,假设您想在发生错误时进行稍微更多的处理,以包装原始异常(例如)。因此,您可以为此创建一个专用的私有方法。在那里看到raise 而不是fail 会很有用,因为rescue 不会在重新抛出之前。
【解决方案2】:

我曾经就这件事与Jim Weirich 进行过交谈,此后我一直使用fail 当我的方法由于某种原因显式失败时使用raise 重新抛出异常。

这是一个来自 Jim 的帖子(几乎是逐字记录他亲自对我说的话): http://www.virtuouscode.com/2014/05/21/jim-weirich-on-exceptions/

以下是帖子中的相关文字,引用自 Jim:

这是我关于异常的基本理念(和其他随机想法)。

当您调用一个方法时,您对该方法将完成什么有一定的期望。正式地,这些期望被称为后置条件。当一个方法不能满足它的后置条件时,它应该抛出一个异常。

要有效地使用此策略,这意味着您必须对契约式设计以及前置条件和后置条件的含义有一点了解。无论如何,我认为这是一件好事。

这里有一些具体的例子。 Rails 模型save 方法:

model.save!
-- post-condition: The model object is saved.

如果模型由于某种原因没有保存,则必须引发异常,因为不满足后置条件。

model.save
-- post-condition: (the model is saved && result == true) ||
                   (the model is not saved && result == false)

如果save实际上并没有保存,那么返回结果将是false,但仍然满足后置条件,所以也不例外。

我觉得有趣的是save! 方法有一个非常简单的后置条件。

关于挽救异常的话题,我认为应用程序应该具有挽救异常的战略要点。大多数情况下几乎不需要救援/重新投掷。您唯一需要救援和重新抛出的情况是当您完成了一半的工作并且您想要撤消某些内容时,请避免部分完成状态。应仔细选择您的战略救援点,以便即使当前操作失败,程序也可以继续其他工作。事务处理程序应该继续进行下一个事务。 Rails 应用程序应该恢复并准备好处理下一个 http 请求。

大多数异常处理程序应该是通用的。由于异常表明某种类型的故障,因此处理程序只需决定在发生故障时要做什么。通常不鼓励对非常具体的异常执行详细的恢复操作,除非处理程序非常接近(调用图)异常点。

异常不应该用于流控制,使用throw/catch。这为真正的故障情况保留了例外情况。

(顺便说一句,因为我使用异常来指示失败,所以我几乎总是在 Ruby 中使用 fail 关键字而不是 raise 关键字。Failraise 是同义词,所以除了以下之外没有区别fail 更清楚地传达了该方法已失败。我使用 raise 的唯一一次是当我捕获异常并重新引发它时,因为这里我 没有 失败,而是明确地并有目的地提出一个例外。这是我遵循的风格问题,但我怀疑很多其他人这样做)。

你有它,我对异常的想法相当漫无边际的内存转储。

我知道有很多风格指南不同意(例如RoboCop 使用的style guide)。我不在乎。吉姆说服了我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    相关资源
    最近更新 更多