什么是在Ruby中的rescue子句中抑制异常的好方法?

时间:2017-01-04 22:40:13

标签: ruby exception error-handling rescue

begin
  do_something
rescue
  Logger.write ...

  ...error handling...
end

问题是,救援 中的代码 可能会引发异常。对于这个用例,我想压制它。

那么,如何将救援包裹起来以抑制异常呢?

1 个答案:

答案 0 :(得分:3)

你自己说了

  

救援救援

例外初始

除了在begin rescue end块中包装代码块之外没有其他特殊方法:

begin
  do_something
rescue
  begin
    Logger.write ...
  rescue
    ...error handling...
  end
end

...除非您使用ActiveSupport:http://api.rubyonrails.org/classes/Kernel.html#method-i-suppress

suppress(Exception) do
  # all exceptions will be suppressed
end

..但它不是一个普通的Ruby东西,我注意到你没有在你的问题中添加一个rails标签。但是,您可以自己实施suppress。或者,只是,这里采取这个:

def suppress(*exception_classes)
  yield
rescue *exception_classes
end

在救援中使用它:

begin
  do_something
rescue
  Logger.write ...

  suppress Exception do
    ...error handling...
  end
end

在普通的Ruby中,它必须一直向下拯救(事实上,suppress只是一个嵌套的救援)但是我只是说,从本质上讲,拯救所有异常是一个坏主意。没有明确说明你正在拯救什么异常,换句话说,通过不将异常类参数传递给rescue你隐含地拯救StandardError这是大多数异常的超类({{3} })。这可能导致很难找到错误。

begin    
rescue
end

..与:

相同
begin
rescue StandardError
end

最好知道你正在拯救什么异常,并明确它:

begin
rescue SomeApiError => e
  # do something when this specific exception occurs
end

有了这个想法,你可以使用级联策略来拯救你的异常:

begin
  # do the thing
rescue SomeApiError => e 
  # specific rescue
rescue SomeOtherError => e
  # more broad error handling
rescue
  # catch all rescue
end

如上所述,只有与引发的异常匹配的rescue子句会运行,但是救援块中的代码不会被后续的救援拯救,只有begin块中的代码才能被抢救。

如果您想拥有一个即使在发生异常时也始终运行的代码块,请使用ensure关键字:

begin
  # code
rescue => e
  # rescue code
ensure
  # this block will always run exception or not
end