为什么在Ruby中“拯救异常=> e”是不好的风格?

时间:2022-10-19 20:23:00

Ryan Davis’s Ruby QuickRef says (without explanation):

Ryan Davis的Ruby QuickRef说(没有解释):

Don’t rescue Exception. EVER. or I will stab you.

不救援例外。永远。否则我会刺死你。

Why not? What’s the right thing to do?

为什么不呢?正确的做法是什么?

6 个解决方案

#1


1198  

TL;DR: Use StandardError instead for general exception catching. When the original exception is re-raised (e.g. when rescuing to log the exception only), rescuing Exception is probably okay.

使用标准符号代替一般的异常捕获。当原始异常被重新启动时(例如,仅当进行日志记录时),挽救异常可能是可行的。


Exception is the root of Ruby's exception hierarchy, so when you rescue Exception you rescue from everything, including subclasses such as SyntaxError, LoadError, and Interrupt.

异常是Ruby异常层次结构的根,因此,当您拯救异常时,您将从所有东西中进行拯救,包括子类,如SyntaxError、LoadError和中断。

Rescuing Interrupt prevents the user from using CTRLC to exit the program.

救援中断阻止用户使用ctrl - lc退出程序。

Rescuing SignalException prevents the program from responding correctly to signals. It will be unkillable except by kill -9.

拯救信号异常阻止程序正确地响应信号。除kill -9外,它将是不可杀死的。

Rescuing SyntaxError means that evals that fail will do so silently.

对SyntaxError的补救意味着失败的事件会悄无声息地发生。

All of these can be shown by running this program, and trying to CTRLC or kill it:

所有这些都可以通过运行这个程序来显示,并试图控制或杀死它:

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

Rescuing from Exception isn't even the default. Doing

从异常中拯救甚至不是默认。做

begin
  # iceberg!
rescue
  # lifeboats
end

does not rescue from Exception, it rescues from StandardError. You should generally specify something more specific than the default StandardError, but rescuing from Exception broadens the scope rather than narrowing it, and can have catastrophic results and make bug-hunting extremely difficult.

不拯救例外,它从标准中拯救。一般来说,您应该指定比默认标准更具体的内容,但是,从异常中进行拯救会拓宽范围,而不是缩小范围,并且可能会带来灾难性的结果,并使bug搜索变得非常困难。


If you have a situation where you do want to rescue from StandardError and you need a variable with the exception, you can use this form:

如果您想要从标准模型中进行补救,并且需要一个带有异常的变量,您可以使用以下形式:

begin
  # iceberg!
rescue => e
  # lifeboats
end

which is equivalent to:

相当于:

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

One of the few common cases where it’s sane to rescue from Exception is for logging/reporting purposes, in which case you should immediately re-raise the exception:

在一些常见的情况下,出于日志/报告的目的,它是正常的,但在这种情况下,您应该立即重新抛出异常:

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

#2


68  

The real rule is: Don't throw away exceptions. The objectivity of the author of your quote is questionable, as evidenced by the fact that it ends with

真正的规则是:不要抛出异常。你引用的作者的客观性是有问题的,因为它的结尾是这样的。

or I will stab you

否则我会刺死你。

Of course, be aware that signals (by default) throw exceptions, and normally long-running processes are terminated through a signal, so catching Exception and not terminating on signal exceptions will make your program very hard to stop. So don't do this:

当然,要注意到信号(默认情况下)抛出异常,通常长时间运行的进程通过一个信号终止,因此捕获异常和不终止信号异常将使您的程序很难停止。所以不要这样做:

#! /usr/bin/ruby

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

No, really, don't do it. Don't even run that to see if it works.

不,真的,别这么做。不要运行它,看它是否有效。

However, say you have a threaded server and you want all exceptions to not:

但是,假设您有一个线程服务器,并且您希望所有的异常都不能:

  1. be ignored (the default)
  2. 被忽略(默认)
  3. stop the server (which happens if you say thread.abort_on_exception = true).
  4. 停止服务器(如果您说线程,就会发生这种情况)。abort_on_exception = true)。

Then this is perfectly acceptable in your connection handling thread:

这在您的连接处理线程中是完全可以接受的:

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

The above works out to a variation of Ruby's default exception handler, with the advantage that it doesn't also kill your program. Rails does this in its request handler.

上面提到的是Ruby的默认异常处理程序的变体,它的优点是它不会破坏您的程序。Rails在其请求处理程序中执行此操作。

Signal exceptions are raised in the main thread. Background threads won't get them, so there is no point in trying to catch them there.

在主线程中增加了信号异常。后台线程不会得到它们,所以试图在那里捕获它们是没有意义的。

This is particularly useful in a production environment, where you do not want your program to simply stop whenever something goes wrong. Then you can take the stack dumps in your logs and add to your code to deal with specific exception further down the call chain and in a more graceful manner.

这在生产环境中特别有用,您不希望您的程序在出现问题时停止。然后,您可以在日志中提取堆栈转储,并添加到代码中,以更加优雅的方式处理调用链上的特定异常。

Note also that there is another Ruby idiom which has much the same effect:

还要注意,还有另一个Ruby习语,它的效果是一样的:

a = do_something rescue "something else"

In this line, if do_something raises an exception, it is caught by Ruby, thrown away, and a is assigned "something else".

在这一行中,如果do_something引发了一个异常,它会被Ruby捕获,被丢弃,而a被赋值为“其他的东西”。

Generally, don't do that, except in special cases where you know you don't need to worry. One example:

一般情况下,不要这样做,除非在特殊情况下,你知道你不需要担心。一个例子:

debugger rescue nil

The debugger function is a rather nice way to set a breakpoint in your code, but if running outside a debugger, and Rails, it raises an exception. Now theoretically you shouldn't be leaving debug code lying around in your program (pff! nobody does that!) but you might want to keep it there for a while for some reason, but not continually run your debugger.

调试器函数是在代码中设置断点的一种很好的方法,但是如果在调试器和Rails之外运行,则会引发异常。现在理论上,您不应该在程序中保留调试代码(pff!但是您可能想要在那里保留它一段时间,因为某些原因,但不能持续运行您的调试器。

Note:

注意:

  1. If you've run someone else's program that catches signal exceptions and ignores them, (say the code above) then:

    如果您运行的是其他人的程序,捕获信号异常并忽略它们,(如上面的代码),那么:

    • in Linux, in a shell, type pgrep ruby, or ps | grep ruby, look for your offending program's PID, and then run kill -9 <PID>.
    • 在Linux中,在shell中,键入pgrep ruby,或ps | grep ruby,查找您的问题程序的PID,然后运行kill -9
    • in Windows, use the Task Manager (CTRL-SHIFT-ESC), go to the "processes" tab, find your process, right click it and select "End process".
    • 在Windows中,使用任务管理器(CTRL-SHIFT-ESC),进入“进程”选项卡,找到您的进程,右键单击并选择“End process”。
  2. If you are working with someone else's program which is, for whatever reason, peppered with these ignore-exception blocks, then putting this at the top of the mainline is one possible cop-out:

    如果你正在和别人的程序一起工作,不管出于什么原因,用这些忽略的异常块,然后把它放在主线的顶部是一种可能的逃避:

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

    This causes the program to respond to the normal termination signals by immediately terminating, bypassing exception handlers, with no cleanup. So it could cause data loss or similar. Be careful!

    这使得程序可以通过立即终止、绕过异常处理程序、不进行清理来响应正常的终止信号。这可能导致数据丢失或类似。小心!

  3. If you need to do this:

    如果你需要这样做:

    begin
      do_something
    rescue Exception => e
      critical_cleanup
      raise
    end
    

    you can actually do this:

    你可以这样做:

    begin
      do_something
    ensure
      critical_cleanup
    end
    

    In the second case, critical cleanup will be called every time, whether or not an exception is thrown.

    在第二种情况下,每次都将调用临界清理,无论是否抛出异常。

#3


42  

Because this captures all exceptions. It's unlikely that your program can recover from any of them.

因为这捕获了所有的异常。你的程序不太可能从任何一个程序中恢复。

You should handle only exceptions that you know how to recover from. If you don't anticipate a certain kind of exception, don't handle it, crash loudly (write details to the log), then diagnose logs and fix code.

您应该只处理您知道如何恢复的异常。如果您没有预料到某种异常,不要处理它,大声地崩溃(将详细信息写入日志),然后诊断日志和修复代码。

Swallowing exceptions is bad, don't do this.

吞咽异常是不好的,不要这样做。

#4


35  

Let's say you are in a car (running Ruby). You recently installed a new steering wheel with the over-the-air upgrade system (which uses eval), but you didn't know one of the programmers messed up on syntax.

假设你在车里(运行Ruby)。您最近安装了一个带有无线升级系统(使用eval)的新方向盘,但是您不知道其中一个程序员把语法搞砸了。

You are on a bridge, and realize you are going a bit towards the railing, so you turn left.

你在一座桥上,意识到你在向栏杆靠近一点,所以你向左转。

def turn_left
  self.turn left:
end

oops! That's probably Not Good™, luckily, Ruby raises a SyntaxError.

哦!这可能不太好,幸运的是,Ruby提出了一个SyntaxError。

The car should stop immediately - right?

汽车应该立即停止,对吗?

Nope.

不。

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

beep beep

哔哔哔哔的声音

Warning: Caught SyntaxError Exception.

警告:抓住SyntaxError例外。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

You notice something is wrong, and you slam on the emergency breaks (^C: Interrupt)

你注意到有什么地方不对劲,然后你猛踩紧急刹车。

beep beep

哔哔哔哔的声音

Warning: Caught Interrupt Exception.

警告:捕获中断异常。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

Yeah - that didn't help much. You're pretty close to the rail, so you put the car in park (killing: SignalException).

是的,那没有多大帮助。你离铁路很近,所以你把车停在公园(杀人:信号异常)。

beep beep

哔哔哔哔的声音

Warning: Caught SignalException Exception.

警告:抓住SignalException例外。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

At the last second, you pull out the keys (kill -9), and the car stops, you slam forward into the steering wheel (the airbag can't inflate because you didn't gracefully stop the program - you terminated it), and the computer in the back of your car slams into the seat in front of it. A half-full can of Coke spills over the papers. The groceries in the back are crushed, and most are covered in egg yolk and milk. The car needs serious repair and cleaning. (Data Loss)

在最后一秒,你拿出钥匙(kill - 9),车停了,你摔到方向盘(安全气囊不能夸大,因为你没有优雅地停止程序——你终止),和电脑在你的车猛烈撞击前面的座位。一罐半满的可乐洒在报纸上。背部的食品被压碎,大部分被蛋黄和牛奶覆盖。这辆汽车需要认真修理和清洗。(数据丢失)

Hopefully you have insurance (Backups). Oh yeah - because the airbag didn't inflate, you're probably hurt (getting fired, etc).

希望你有保险(备份)。哦,是的-因为那个安全气囊没有充气,你很可能受伤了(被解雇了等等)。


But wait! There's more reasons why you might want to use rescue Exception => e!

但是等等!有更多的理由可以解释为什么你想使用拯救异常=> e!

Let's say you're that car, and you want to make sure the airbag inflates if the car is going more than 5mph before stopping.

假设你是那辆车,你要确保安全气囊在停车前超过每小时5英里的速度膨胀。

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

Here's the exception to the rule: You can catch Exception only if you re-raise the exception. So, a better rule is to never swallow Exception, and always re-raise the error.

这里是规则的例外:只有在重新抛出异常时才可以捕获异常。所以,一个更好的规则是永远不要吞下异常,并且总是重新抛出错误。

But adding rescue is both easy to forget in a language like Ruby, and putting a rescue statement right before re-raising an issue feels a little non-DRY. And you do not want to forget the raise statement. And if you do, good luck trying to find that error.

但是,在像Ruby这样的语言中,添加救援是很容易的,而且在重新提出一个问题之前,把救援声明放在一边,感觉有点不枯燥。而且你也不想忘记加薪声明。如果你这样做了,祝你好运,试图找到那个错误。

Thankfully, Ruby is awesome, you can just use the ensure keyword, which makes sure the code runs. The ensure keyword will run the code no matter what - if an exception is thrown, if one isn't, the only exception being if the world ends (or other unlikely events).

值得庆幸的是,Ruby是非常棒的,您可以使用确保关键字,确保代码运行。“确保关键字”将运行代码,无论如何——如果抛出一个异常,如果一个不是,那么唯一的例外就是世界结束(或者其他不太可能发生的事件)。

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

Boom! And that code should run anyways. The only reason you should use rescue Exception => e is if you need access to the exception, or if you only want code to run on an exception. And remember to re-raise the error. Every time. Or you will have 3 people stabbing you (including your boss).

繁荣!这段代码应该可以运行。您应该使用rescue Exception的唯一原因是,如果您需要访问异常,或者只希望代码运行在异常上。记住要重新提出错误。每一次。或者你会有3个人刺伤你(包括你的老板)。


TL;DR

Don't rescue Exception => e (and not re-raise the exception) - or you might drive off a bridge.

不要拯救异常=> e(不要重新引发异常)——否则你可能会开车离开桥。

#5


8  

That's a specific case of the rule that you shouldn't catch any exception you don't know how to handle. If you don't know how to handle it, it's always better to let some other part of the system catch and handle it.

这是规则的一个特例,你不应该捕获任何不知道如何处理的异常。如果您不知道如何处理它,那么最好让系统的其他部分捕获并处理它。

#6


1  

This will also hide bugs from you, for example if you mistyped a method name:

这也将隐藏来自您的bug,例如,如果您输入了一个方法名称:

def my_fun
  "my_fun"
end

begin
 # you mistypped my_fun to my_func
 my_func # my_func()
rescue Exception
  # rescued NameError (or NoMethodError if you called method with parenthesis)
end

#1


1198  

TL;DR: Use StandardError instead for general exception catching. When the original exception is re-raised (e.g. when rescuing to log the exception only), rescuing Exception is probably okay.

使用标准符号代替一般的异常捕获。当原始异常被重新启动时(例如,仅当进行日志记录时),挽救异常可能是可行的。


Exception is the root of Ruby's exception hierarchy, so when you rescue Exception you rescue from everything, including subclasses such as SyntaxError, LoadError, and Interrupt.

异常是Ruby异常层次结构的根,因此,当您拯救异常时,您将从所有东西中进行拯救,包括子类,如SyntaxError、LoadError和中断。

Rescuing Interrupt prevents the user from using CTRLC to exit the program.

救援中断阻止用户使用ctrl - lc退出程序。

Rescuing SignalException prevents the program from responding correctly to signals. It will be unkillable except by kill -9.

拯救信号异常阻止程序正确地响应信号。除kill -9外,它将是不可杀死的。

Rescuing SyntaxError means that evals that fail will do so silently.

对SyntaxError的补救意味着失败的事件会悄无声息地发生。

All of these can be shown by running this program, and trying to CTRLC or kill it:

所有这些都可以通过运行这个程序来显示,并试图控制或杀死它:

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

Rescuing from Exception isn't even the default. Doing

从异常中拯救甚至不是默认。做

begin
  # iceberg!
rescue
  # lifeboats
end

does not rescue from Exception, it rescues from StandardError. You should generally specify something more specific than the default StandardError, but rescuing from Exception broadens the scope rather than narrowing it, and can have catastrophic results and make bug-hunting extremely difficult.

不拯救例外,它从标准中拯救。一般来说,您应该指定比默认标准更具体的内容,但是,从异常中进行拯救会拓宽范围,而不是缩小范围,并且可能会带来灾难性的结果,并使bug搜索变得非常困难。


If you have a situation where you do want to rescue from StandardError and you need a variable with the exception, you can use this form:

如果您想要从标准模型中进行补救,并且需要一个带有异常的变量,您可以使用以下形式:

begin
  # iceberg!
rescue => e
  # lifeboats
end

which is equivalent to:

相当于:

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

One of the few common cases where it’s sane to rescue from Exception is for logging/reporting purposes, in which case you should immediately re-raise the exception:

在一些常见的情况下,出于日志/报告的目的,它是正常的,但在这种情况下,您应该立即重新抛出异常:

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

#2


68  

The real rule is: Don't throw away exceptions. The objectivity of the author of your quote is questionable, as evidenced by the fact that it ends with

真正的规则是:不要抛出异常。你引用的作者的客观性是有问题的,因为它的结尾是这样的。

or I will stab you

否则我会刺死你。

Of course, be aware that signals (by default) throw exceptions, and normally long-running processes are terminated through a signal, so catching Exception and not terminating on signal exceptions will make your program very hard to stop. So don't do this:

当然,要注意到信号(默认情况下)抛出异常,通常长时间运行的进程通过一个信号终止,因此捕获异常和不终止信号异常将使您的程序很难停止。所以不要这样做:

#! /usr/bin/ruby

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

No, really, don't do it. Don't even run that to see if it works.

不,真的,别这么做。不要运行它,看它是否有效。

However, say you have a threaded server and you want all exceptions to not:

但是,假设您有一个线程服务器,并且您希望所有的异常都不能:

  1. be ignored (the default)
  2. 被忽略(默认)
  3. stop the server (which happens if you say thread.abort_on_exception = true).
  4. 停止服务器(如果您说线程,就会发生这种情况)。abort_on_exception = true)。

Then this is perfectly acceptable in your connection handling thread:

这在您的连接处理线程中是完全可以接受的:

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

The above works out to a variation of Ruby's default exception handler, with the advantage that it doesn't also kill your program. Rails does this in its request handler.

上面提到的是Ruby的默认异常处理程序的变体,它的优点是它不会破坏您的程序。Rails在其请求处理程序中执行此操作。

Signal exceptions are raised in the main thread. Background threads won't get them, so there is no point in trying to catch them there.

在主线程中增加了信号异常。后台线程不会得到它们,所以试图在那里捕获它们是没有意义的。

This is particularly useful in a production environment, where you do not want your program to simply stop whenever something goes wrong. Then you can take the stack dumps in your logs and add to your code to deal with specific exception further down the call chain and in a more graceful manner.

这在生产环境中特别有用,您不希望您的程序在出现问题时停止。然后,您可以在日志中提取堆栈转储,并添加到代码中,以更加优雅的方式处理调用链上的特定异常。

Note also that there is another Ruby idiom which has much the same effect:

还要注意,还有另一个Ruby习语,它的效果是一样的:

a = do_something rescue "something else"

In this line, if do_something raises an exception, it is caught by Ruby, thrown away, and a is assigned "something else".

在这一行中,如果do_something引发了一个异常,它会被Ruby捕获,被丢弃,而a被赋值为“其他的东西”。

Generally, don't do that, except in special cases where you know you don't need to worry. One example:

一般情况下,不要这样做,除非在特殊情况下,你知道你不需要担心。一个例子:

debugger rescue nil

The debugger function is a rather nice way to set a breakpoint in your code, but if running outside a debugger, and Rails, it raises an exception. Now theoretically you shouldn't be leaving debug code lying around in your program (pff! nobody does that!) but you might want to keep it there for a while for some reason, but not continually run your debugger.

调试器函数是在代码中设置断点的一种很好的方法,但是如果在调试器和Rails之外运行,则会引发异常。现在理论上,您不应该在程序中保留调试代码(pff!但是您可能想要在那里保留它一段时间,因为某些原因,但不能持续运行您的调试器。

Note:

注意:

  1. If you've run someone else's program that catches signal exceptions and ignores them, (say the code above) then:

    如果您运行的是其他人的程序,捕获信号异常并忽略它们,(如上面的代码),那么:

    • in Linux, in a shell, type pgrep ruby, or ps | grep ruby, look for your offending program's PID, and then run kill -9 <PID>.
    • 在Linux中,在shell中,键入pgrep ruby,或ps | grep ruby,查找您的问题程序的PID,然后运行kill -9
    • in Windows, use the Task Manager (CTRL-SHIFT-ESC), go to the "processes" tab, find your process, right click it and select "End process".
    • 在Windows中,使用任务管理器(CTRL-SHIFT-ESC),进入“进程”选项卡,找到您的进程,右键单击并选择“End process”。
  2. If you are working with someone else's program which is, for whatever reason, peppered with these ignore-exception blocks, then putting this at the top of the mainline is one possible cop-out:

    如果你正在和别人的程序一起工作,不管出于什么原因,用这些忽略的异常块,然后把它放在主线的顶部是一种可能的逃避:

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

    This causes the program to respond to the normal termination signals by immediately terminating, bypassing exception handlers, with no cleanup. So it could cause data loss or similar. Be careful!

    这使得程序可以通过立即终止、绕过异常处理程序、不进行清理来响应正常的终止信号。这可能导致数据丢失或类似。小心!

  3. If you need to do this:

    如果你需要这样做:

    begin
      do_something
    rescue Exception => e
      critical_cleanup
      raise
    end
    

    you can actually do this:

    你可以这样做:

    begin
      do_something
    ensure
      critical_cleanup
    end
    

    In the second case, critical cleanup will be called every time, whether or not an exception is thrown.

    在第二种情况下,每次都将调用临界清理,无论是否抛出异常。

#3


42  

Because this captures all exceptions. It's unlikely that your program can recover from any of them.

因为这捕获了所有的异常。你的程序不太可能从任何一个程序中恢复。

You should handle only exceptions that you know how to recover from. If you don't anticipate a certain kind of exception, don't handle it, crash loudly (write details to the log), then diagnose logs and fix code.

您应该只处理您知道如何恢复的异常。如果您没有预料到某种异常,不要处理它,大声地崩溃(将详细信息写入日志),然后诊断日志和修复代码。

Swallowing exceptions is bad, don't do this.

吞咽异常是不好的,不要这样做。

#4


35  

Let's say you are in a car (running Ruby). You recently installed a new steering wheel with the over-the-air upgrade system (which uses eval), but you didn't know one of the programmers messed up on syntax.

假设你在车里(运行Ruby)。您最近安装了一个带有无线升级系统(使用eval)的新方向盘,但是您不知道其中一个程序员把语法搞砸了。

You are on a bridge, and realize you are going a bit towards the railing, so you turn left.

你在一座桥上,意识到你在向栏杆靠近一点,所以你向左转。

def turn_left
  self.turn left:
end

oops! That's probably Not Good™, luckily, Ruby raises a SyntaxError.

哦!这可能不太好,幸运的是,Ruby提出了一个SyntaxError。

The car should stop immediately - right?

汽车应该立即停止,对吗?

Nope.

不。

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

beep beep

哔哔哔哔的声音

Warning: Caught SyntaxError Exception.

警告:抓住SyntaxError例外。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

You notice something is wrong, and you slam on the emergency breaks (^C: Interrupt)

你注意到有什么地方不对劲,然后你猛踩紧急刹车。

beep beep

哔哔哔哔的声音

Warning: Caught Interrupt Exception.

警告:捕获中断异常。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

Yeah - that didn't help much. You're pretty close to the rail, so you put the car in park (killing: SignalException).

是的,那没有多大帮助。你离铁路很近,所以你把车停在公园(杀人:信号异常)。

beep beep

哔哔哔哔的声音

Warning: Caught SignalException Exception.

警告:抓住SignalException例外。

Info: Logged Error - Continuing Process.

信息:记录错误-持续过程。

At the last second, you pull out the keys (kill -9), and the car stops, you slam forward into the steering wheel (the airbag can't inflate because you didn't gracefully stop the program - you terminated it), and the computer in the back of your car slams into the seat in front of it. A half-full can of Coke spills over the papers. The groceries in the back are crushed, and most are covered in egg yolk and milk. The car needs serious repair and cleaning. (Data Loss)

在最后一秒,你拿出钥匙(kill - 9),车停了,你摔到方向盘(安全气囊不能夸大,因为你没有优雅地停止程序——你终止),和电脑在你的车猛烈撞击前面的座位。一罐半满的可乐洒在报纸上。背部的食品被压碎,大部分被蛋黄和牛奶覆盖。这辆汽车需要认真修理和清洗。(数据丢失)

Hopefully you have insurance (Backups). Oh yeah - because the airbag didn't inflate, you're probably hurt (getting fired, etc).

希望你有保险(备份)。哦,是的-因为那个安全气囊没有充气,你很可能受伤了(被解雇了等等)。


But wait! There's more reasons why you might want to use rescue Exception => e!

但是等等!有更多的理由可以解释为什么你想使用拯救异常=> e!

Let's say you're that car, and you want to make sure the airbag inflates if the car is going more than 5mph before stopping.

假设你是那辆车,你要确保安全气囊在停车前超过每小时5英里的速度膨胀。

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

Here's the exception to the rule: You can catch Exception only if you re-raise the exception. So, a better rule is to never swallow Exception, and always re-raise the error.

这里是规则的例外:只有在重新抛出异常时才可以捕获异常。所以,一个更好的规则是永远不要吞下异常,并且总是重新抛出错误。

But adding rescue is both easy to forget in a language like Ruby, and putting a rescue statement right before re-raising an issue feels a little non-DRY. And you do not want to forget the raise statement. And if you do, good luck trying to find that error.

但是,在像Ruby这样的语言中,添加救援是很容易的,而且在重新提出一个问题之前,把救援声明放在一边,感觉有点不枯燥。而且你也不想忘记加薪声明。如果你这样做了,祝你好运,试图找到那个错误。

Thankfully, Ruby is awesome, you can just use the ensure keyword, which makes sure the code runs. The ensure keyword will run the code no matter what - if an exception is thrown, if one isn't, the only exception being if the world ends (or other unlikely events).

值得庆幸的是,Ruby是非常棒的,您可以使用确保关键字,确保代码运行。“确保关键字”将运行代码,无论如何——如果抛出一个异常,如果一个不是,那么唯一的例外就是世界结束(或者其他不太可能发生的事件)。

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

Boom! And that code should run anyways. The only reason you should use rescue Exception => e is if you need access to the exception, or if you only want code to run on an exception. And remember to re-raise the error. Every time. Or you will have 3 people stabbing you (including your boss).

繁荣!这段代码应该可以运行。您应该使用rescue Exception的唯一原因是,如果您需要访问异常,或者只希望代码运行在异常上。记住要重新提出错误。每一次。或者你会有3个人刺伤你(包括你的老板)。


TL;DR

Don't rescue Exception => e (and not re-raise the exception) - or you might drive off a bridge.

不要拯救异常=> e(不要重新引发异常)——否则你可能会开车离开桥。

#5


8  

That's a specific case of the rule that you shouldn't catch any exception you don't know how to handle. If you don't know how to handle it, it's always better to let some other part of the system catch and handle it.

这是规则的一个特例,你不应该捕获任何不知道如何处理的异常。如果您不知道如何处理它,那么最好让系统的其他部分捕获并处理它。

#6


1  

This will also hide bugs from you, for example if you mistyped a method name:

这也将隐藏来自您的bug,例如,如果您输入了一个方法名称:

def my_fun
  "my_fun"
end

begin
 # you mistypped my_fun to my_func
 my_func # my_func()
rescue Exception
  # rescued NameError (or NoMethodError if you called method with parenthesis)
end