当我''救援''重试'时Ruby不“确保”

时间:2011-06-03 06:00:26

标签: ruby rescue

考虑这个begin-rescue-ensure块:

attempts=0
begin
  make_service_call()
rescue Exception
  retry unless attempts>2
  exit -1
ensure
  attemps += 1
end

如果按原样运行该代码,则会引发异常,因为没有名为'make_service_call()'的函数。所以,它重试了。但它会陷入无限循环,因为控件永远不会因为“重试”而“确保”。不应该'确保'块的一部分确保其中的代码无论在'begin'或'rescue'中发生什么都会被执行?

当然我可以在'开始'中增加计数 - 这不是重点。我只是问'确保'这个问题,以便明确一些。

2 个答案:

答案 0 :(得分:18)

ensure部分在离开begin语句时执行(无论如何)但是当你retry时,你只是在声明中移动,所以确保部分不会被执行。

尝试使用此版本的示例,以便更好地了解正在发生的事情:

attempts = 0
begin
  make_service_call()
rescue Exception
  attempts += 1
  retry unless attempts > 2
  exit -1
ensure
  puts "ensure! #{attempts}"
end

答案 1 :(得分:3)

ensure代码执行一次,就在代码块退出之前,在那时被调用。

但是由于unless attempts>2条件,以及ensure只会在“代码退出之前”被调用的事实(例如由于exit -1attempts += 1将不会执行,因此存在无限循环。

ensure与C ++中的__finally类似:您可以catch例外,然后使用goto:但finally将不会被调用,直到该函数实际上即将退出。