Retry

如果你认为错误情况可能是暂时的或者可以被纠正(由用户),你可以使用关键字 retry 重新运行 begin..end 块中的所有代码,如此示例中如果发生 ZeroDivisionError 等错误则会提示用户重新输入一个值:

retry.rb
  1. def doCalc
  2. begin
  3. print( "Enter a number: " )
  4. aNum = gets().chomp()
  5. result = 100 / aNum.to_i
  6. rescue Exception => e
  7. result = 0
  8. puts( "Error: " + e + "\nPlease try again." )
  9. retry # retry on exception
  10. else
  11. msg = "Result = #{result}"
  12. ensure
  13. msg = "You entered '#{aNum}'. " + msg
  14. end
  15. return msg
  16. end

当然,存在这样的危险:错误可能不像你想象的那样是暂时的,如果你使用 retry,你必须要提供明确定义的退出(exit)条件,以确保代码在固定次数的尝试后停止执行。

例如,你可以在 begin 子句中递增一个局部变量(如果这样做,请确保它在任何可能产生异常的代码之前递增,因为一旦发生异常,那些剩下的预先为 rescue 子句关联的代码将被跳过!)。然后在 rescue 部分测试该变量的值,如下所示:

  1. rescue Exception => e
  2. if aValue < someValue then
  3. retry
  4. end

这是一个完整的示例,其中我测试名为 tries 的变量的值,以确保在异常处理块退出之前在不出错的情况下尝试重新运行代码不超过三次:

  1. def doCalc
  2. tries = 0
  3. begin
  4. print( "Enter a number: " )
  5. tries += 1
  6. aNum = gets().chomp()
  7. result = 100 / aNum.to_i
  8. rescue Exception => e
  9. msg = "Error: " + e
  10. puts( msg )
  11. puts( "tries = #{tries}" )
  12. result = 0
  13. if tries < 3 then # set a fixed number of retries
  14. retry
  15. end
  16. else
  17. msg = "Result = #{result}"
  18. ensure
  19. msg = "You entered '#{aNum}'. " + msg
  20. end
  21. return msg
  22. end