Exception 处理
异常在 begin/end 块中被捕获
begin # code that might raise rescue # handle exception end
如果您在方法内部,则不需要使用 begin 或 end,除非您想限制捕获异常的范围
def my_method # ... rescue # ... end
对于 class、module 和 block 也是如此
[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
异常从顶部开始与 rescue 部分匹配,并且只匹配一次。如果在 begin 部分引发了 ArgumentError,它将不会在 StandardError 部分被处理。
您可以重试捕获的异常
begin # ... rescue # do something that may change the result of the begin block retry end
执行将从 begin 块的开头恢复,因此请小心不要创建无限循环。
retry 只能在 rescue 块内部使用,所有其他用法都会引发 SyntaxError。如果您想重试块迭代,请使用 redo。有关详细信息,请参阅 控制表达式。
要始终运行某些代码,无论是否引发了异常,请使用 ensure
begin # ... rescue # ... ensure # this always runs BUT does not implicitly return the last evaluated statement. end
您也可以在未引发异常时运行某些代码
begin # ... rescue # ... else # this runs only when no exception was raised AND return the last evaluated statement ensure # this always runs. # It is evaluated after the evaluation of either the `rescue` or the `else` block. # It will not return implicitly. end
注意:如果没有在 ensure 块中显式 return,begin/end 块将返回进入 ensure 块之前的最后一个已计算语句。