Ryan 戴维斯拼音指南说 (而无需说明)︰

不救异常。以往任何时候都。或将您 stab 其状态。

为什么不呢?要做的事情是什么?

2012-04-06 19:17:47
问题评论:

我知道答案,我想只问一下侥幸︰ 有人将调高的最佳答案,因为我不能找到一个优秀与搜索几分钟。到目前为止无答案真的正确。

然后您可能会编写自己吗?:)

我非常不善于对此处的暴力。它不仅仅编程。

在 Ruby 异常具有很好的Ruby 异常层次结构中看一看这篇文章.

回答:

Exception情况是根的Ruby 的异常层次结构,因此当您您rescue Exception救从所有内容,包括如SyntaxErrorLoadError,和Interrupt的子类.

RescuingInterrupt会阻止用户使用CTRLC退出程序。

Rescuing SignalException可防止程序正确响应信号。它将结束除由kill -9.

Rescuing SyntaxError意味着eval的失效会因此悄悄进行。

可以通过运行此程序,并尝试显示所有这些CTRLCkill它︰

loop do
  begin
    sleep 1
    eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
  rescue Exception
    puts "I refuse to fail or be stopped!"
  end
end

Rescuing 从Exception甚至没有默认值。这样做

begin
  # iceberg!
rescue
  # lifeboats
end

不会不救从Exception,它 rescues 从StandardError通常应指定比默认StandardError,但 rescuing 从Exception拓宽了范围而不是收缩,更具体的内容,并可以有灾难性的结果和使 bug 搜寻非常困难。


如果您有其中要救从StandardError ,您需要与该异常变量的情况下,您可以使用此窗体︰

begin
  # iceberg!
rescue => e
  # lifeboats
end

它等效于︰

begin
  # iceberg!
rescue StandardError => e
  # lifeboats
end

日志记录/报告的目的很清醒,从Exception救几个常见的案例之一是,在这种情况下您应该立即重新引发异常︰

begin
  # iceberg?
rescue Exception => e
  # do some logging
  raise e  # not enough lifeboats ;)
end

因此,这就像在 java 中捕捉Throwable

如果您正在重新引发该异常,则在不忽略它,因为,它是很好,但我只想知道它再发生的 @Excalibur 让它引起连锁反应。通常出于日志记录。

这一建议非常适合清理 Ruby 环境。但不幸的是大量的 gem 已创建直接降从异常的异常。我们环境中有 30 种︰ 如 OpenID::Server::EncodingError,OAuth::InvalidRequest,HTMLTokenizerSample。这些都是非常想要标准修复块中捕获的异常。遗憾的是,Ruby 中的任何可以防止或甚至遏制直接从异常继承的 gem--甚至命名为非直观。

@JonathanSwartz 然后拯救从这些特定子类,而不是例外。更多特定几乎始终是更好地、 更清楚。

@JonathanSwartz-我将 bug gem 时,系统创建更改其异常的继承者。就个人而言,我喜欢我以前有降从 MyGemException,以便您可以如果想救的所有异常。

真正的规则是︰ 不要将丢弃的异常。您作者的客观性是报价的可疑的事实证明它结束增涨

或将您 stab 其状态

当然,请注意,(默认) 的信号引发异常,通常长时间运行的进程被终止通过信号,以便捕获异常并不终止信号的异常会使您的程序很难停止。所以千万不要这样做︰

#! /usr/bin/ruby

while true do
  begin
    line = STDIN.gets
    # heavy processing
  rescue Exception => e
    puts "caught exception #{e}! ohnoes!"
  end
end

不,真的,不做。甚至不要运行程序以查看其是否正常工作。

但是,假设您有一个线程的服务器和所需的所有例外项不︰

  1. 被忽略 (默认值)
  2. 停止服务器 (如果您说发生thread.abort_on_exception = true).

然后,这是完全可以接受的处理线程连接中︰

begin
  # do stuff
rescue Exception => e
  myLogger.error("uncaught #{e} exception while handling connection: #{e.message}")
    myLogger.error("Stack trace: #{backtrace.map {|l| "  #{l}
"}.join}")
end

Ruby 的缺省异常处理程序,它也不会终止程序的优点的变体为上述工作出。Rails 的请求处理程序中执行此操作。

在主线程中引发的异常信号。后台线程不会获得它们,以便在尝试捕捉它们有没有点。

这是特别有用,在生产环境中,不要想止步不前时一些程序出现错误的位置。然后可以执行堆栈转储日志中,并将添加到您的代码以处理特定异常进一步下调用链和更宽容的方式。

此外请注意,没有另一个拼音用法的效果大体相同︰

a = do_something rescue "something else"

这行,如果do_something引发异常时,它捕捉到的红宝石,丢弃,并a指派"something else".

通常情况下,不必这么做,除非在特殊情况下,您知道您不需要担心。举个例子︰

debugger rescue nil

debugger函数是在代码中设置断点的而不是较好方法,但如果运行调试器和轨道之外,它将引发异常。现在,从理论上说您不应该走出调试代码随处乱放在程序中 (pff ! 没有人执行此 !),但您可能希望使其那里一段时间由于某种原因,但不是连续运行调试器。

注意︰

  1. 如果您已经运行其他人的程序捕获信号异常并忽略它们 (比如上面的代码),然后︰

    • 在 Linux 中,shell 中键入pgrep ruby,或ps | grep ruby、 寻找恶意程序的 PID,并运行kill -9 <PID>.
    • 在 Windows 中,使用任务管理器 (CTRL-SHIFT-ESC),请转到"进程"选项卡上,查找您的流程,右击它并选择"结束进程"。
  2. 如果您正在使用其他人的程序是,不管是什么原因,收到与这些忽略异常块,则将此放在顶部的主线是一个可能的 cop-out:

    %W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
    

    这会导致程序正常终止信号响应通过立即终止,绕过异常处理程序,没有清理因此,它可能会导致数据丢失或类似。小心!

  3. 如果您需要执行此操作︰

    begin
      do_something
    rescue Exception => e
      critical_cleanup
      raise
    end
    

    实际上可以执行此操作︰

    begin
      do_something
    ensure
      critical_cleanup
    end
    

    第二种情况下,每次,无论引发异常,将调用critical cleanup

很抱歉,这是不正确。服务器永远不应救异常和不执行任何操作,但其记录。它将通过使其结束除kill -9.

修正的答案。

您在注 3 中的示例不是 equivilant,ensure无论是否引发异常或rescue将只有在运行时引发异常时,运行。

它们不是 /exactly/ 的等效项,但我不能弄清楚如何用于简单地表达并不丑陋的方式等。

之后开始挽救阻止在第一个示例中,只需添加另一个 critical_cleanup 调用。我同意不是最优雅的代码,但第二个示例显然是正规的方式,这样做只一个小的 inelegance 的示例的一部分。

因为这将捕获所有异常。很可能您的程序可以恢复从任何这些。

应处理您知道如何从恢复的异常。如果您没有预料到一种特定类型的异常,不处理它,,声音太大崩溃 (写的详细信息写入日志),然后诊断日志,并修复代码。

忽略异常错误,千万不要这样做。

让我们假设在 (运行 Ruby) 一辆汽车。最近安装了新的方向盘与空中升级系统 (它使用eval),但不知道全乱了,在语法上的程序员之一。

在一座桥梁,并意识到要有点朝铁栏杆,以便打开左边。

def turn_left
  self.turn left:
end

天哪 !这就是可能不是什么好事™,幸运的是,Ruby 会引发SyntaxError.

立即向右-,汽车应该停止吗?

不对。

begin
  #...
  eval self.steering_wheel
  #...
rescue Exception => e
  self.beep
  self.log "Caught #{e}.", :warn
  self.log "Logged Error - Continuing Process.", :info
end

蜂鸣声蜂鸣音

警告︰ 捕获到 SyntaxError 异常。

信息︰ 记录错误-继续进程。

您发现有问题,而且您 slam 紧急中断 (^CInterrupt)

蜂鸣声蜂鸣音

警告︰ 捕获到中断异常。

信息︰ 记录错误-继续进程。

是的没有帮助很多。您是相当接近导轨,以便将车放在停车场 (killing: SignalException).

蜂鸣声蜂鸣音

警告︰ 捕获到 SignalException 异常。

信息︰ 记录错误-继续进程。

在最后一秒,拉出 (kill -9),键和汽车停止,slam 到方向盘的向前 (airbag 不能使膨胀因为正常没有停止该程序-您终止它),并且您的汽车后面的计算机 slams 到前面的座位。半可 Coke 泼溅的论文上。失败又在后面食品,和大多数涉及 yolk 鸡蛋和牛奶。汽车需求严重维修和清洗。(数据丢失)

但愿您有保险 (备份)。哦是-airbag 不放,因为你可能会伤害 (得到激发,等等)。


但是等等 !没有更多的原因,您可能需要使用rescue Exception => e!

让我们假设你那辆车,并且您想要确保 airbag 放大如果汽车将超过 5 mph 之前停止。

 begin 
    # do driving stuff
 rescue Exception => e
    self.airbags.inflate if self.speed >= 5.mph 
    raise
 end

下面是规则的例外︰Exception再次引发异常的情况下,才可以捕捉。因此,一个更好的规则是永远不会处理Exception,并始终重新引发该错误。

但添加修复是既容易忘记像拼音,并将修复语句之前重新引发一个问题大家都有点非干放右的语言中。并且您想要忘记raise语句。并试图找到该错误如果那样的话,祝你好运。

幸运的是,Ruby 非常棒,您可以只使用ensure关键字,可以确保代码将会运行。ensure关键字将运行这段代码无论如何-如果引发异常,如果一个不是,只异常被世界结束 (或其他不太可能发生的事件)。

 begin 
    # do driving stuff
 ensure
    self.airbags.inflate if self.speed >= 5.mph 
 end

繁荣 !然后,代码应继续运行。应使用的唯一原因rescue Exception => e如果您需要访问该异常,或者如果您只是希望在异常上运行代码。并记住重新引发该错误。每次。或者您将 stabbing (包括您的老板) 的 3 人。


TL; 灾难恢复

rescue Exception => e (和重新引发异常)-或您可能推动关闭一座桥梁。

这是规则不应捕获任何异常,不知道如何处理特定的 case。如果您不知道如何处理它,总是更好一些,让系统的某些其他部分捕获并处理它。

请输入您的翻译

Why is it bad style to `rescue Exception => e` in Ruby?

确认取消