Exception 处理

异常在 begin/end 块中被捕获

begin
  # code that might raise
rescue
  # handle exception
end

如果你在方法内部,你不必使用 beginend,除非你想限制被捕获异常的范围

def my_method
  # ...
rescue
  # ...
end

对于 classmoduleblock 也是如此

[0, 1, 2].map do |i|
  10 / i
rescue ZeroDivisionError
  nil
end
#=> [nil, 10, 5]

你可以在 rescue 行的末尾使用 => variable_name 将异常分配给局部变量

begin
  # ...
rescue => exception
  warn exception.message
  raise # re-raise the current exception
end

默认情况下,StandardError 及其子类会被救援。您可以通过在 rescue 后列出特定的异常类(及其子类)来救援它们

begin
  # ...
rescue ArgumentError, NameError
  # handle ArgumentError or NameError
end

您可以用不同的方式救援不同类型的异常

begin
  # ...
rescue ArgumentError
  # handle ArgumentError
rescue NameError
  # handle NameError
rescue
  # handle any StandardError
end

异常与从顶部开始的救援部分匹配,并且只匹配一次。如果在 begin 部分引发 ArgumentError,则不会在 StandardError 部分中处理它。

您可以重试被救援的异常

begin
  # ...
rescue
  # do something that may change the result of the begin block
  retry
end

执行将在 begin 块的开头恢复,所以小心不要创建无限循环。

在救援块内部是 retry 的唯一有效位置,所有其他用途都会引发 SyntaxError。如果您希望重试块迭代,请使用 redo。有关详细信息,请参阅 控制表达式

无论是否引发异常,始终运行一些代码,请使用 ensure

begin
  # ...
rescue
  # ...
ensure
  # this always runs
end

当未引发异常时,您还可以运行一些代码

begin
  # ...
rescue
  # ...
else
  # this runs only when no exception was raised
ensure
  # ...
end