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

B S*_*ven 0 ruby error-handling exception rescue

begin
  do_something
rescue
  Logger.write ...

  ...error handling...
end
Run Code Online (Sandbox Code Playgroud)

问题是救援中的代码可能引发异常。对于此用例,我想取消它。

那么,如何在救援中包装救援以抑制Exception?

Die*_*zar 5

你自己说的

营救工作

例外开始

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

begin
  do_something
rescue
  begin
    Logger.write ...
  rescue
    ...error handling...
  end
end
Run Code Online (Sandbox Code Playgroud)

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

suppress(Exception) do
  # all exceptions will be suppressed
end
Run Code Online (Sandbox Code Playgroud)

..但这不是普通的Ruby,我注意到您没有在问题中添加rails标记。虽然,您可以实现suppress自己。或者,就在这里:

def suppress(*exception_classes)
  yield
rescue *exception_classes
end
Run Code Online (Sandbox Code Playgroud)

在救援中使用它:

begin
  do_something
rescue
  Logger.write ...

  suppress Exception do
    ...error handling...
  end
end
Run Code Online (Sandbox Code Playgroud)

在普通的老式Ruby中,必须一直进行救援(实际上,suppress这只是一个嵌套的救援),但是让我说,要救援所有异常,从本质上讲,是不明确指出您的异常是一个坏主意。换句话说,通过不向rescue您传递异常类参数来进行抢救StandardError,即隐式抢救了大多数异常的超类(此处提供更多信息)。这可能导致难以发现错误。

begin    
rescue
end
Run Code Online (Sandbox Code Playgroud)

..是相同的:

begin
rescue StandardError
end
Run Code Online (Sandbox Code Playgroud)

最好知道要救援的异常并对其进行明确说明:

begin
rescue SomeApiError => e
  # do something when this specific exception occurs
end
Run Code Online (Sandbox Code Playgroud)

有了这一点,您可以使用级联策略来挽救您的异常:

begin
  # do the thing
rescue SomeApiError => e 
  # specific rescue
rescue SomeOtherError => e
  # more broad error handling
rescue
  # catch all rescue
end
Run Code Online (Sandbox Code Playgroud)

通过上面的操作,只有与所引发的异常相匹配的救援子句才会运行,但是,救援块中的代码将不会被后续救援救援,只有该begin块中的代码是可救援的。

如果要使代码块即使在发生异常的情况下也始终运行,请使用ensure关键字:

begin
  # code
rescue => e
  # rescue code
ensure
  # this block will always run exception or not
end
Run Code Online (Sandbox Code Playgroud)