重试语句在Ruby中如何工作?

时间:2019-05-08 16:25:38

标签: ruby iterator retry-logic

我刚刚开始使用Ruby,但是我遵循的手册似乎已经过时了。我一直在做一些研究,但一直找不到明确的答案。

该手册在应作为循环的方法中使用了'retry'关键字,但该方法在没有begin / rescue块的情况下使用,当您强制将'retry'关键字放入其中时,行为似乎大不相同一个开始/救援块。

我尝试了很多事情: -第一个方法是在方法开始时使用“ begin”关键字,并在重试点使用“ raise”,然后分别使用“ rescue”;重试;结束;'。 -最后一个在外部使用了'begin / rescue'块,包装了方法的调用。

按照手册中的逻辑,只有最后一个可以正常工作。

有一些例子:

手册中的代码如下:

def WHILE(cond)
  return if not cond
  yield
  retry
end
i=0; WHILE(i<3) {print i; i+=1}

结果: 012

我尝试了以下操作:

def WHILE(cond)
  begin
    return if not cond
    yield
    raise
  rescue
    retry
  end
end
i=0; WHILE(i<3) {print i; i+=1}

结果: 无限数

def WHILE(cond)
  return if not cond
  yield
end
i=0; begin; WHILE(i<3) {print i; i+=1}; raise; rescue; retry; end

结果: 012 (加上明显的无限循环,什么也不打印)

我希望你不要让我摆脱这个存在的疑问,但这是我的结论。

在强制使用'retry'关键字的begin / rescue块之前,它可以以一种不再使用的方式使用,重复方法的调用 位于该方法之内

现在,它只是跳转到“开始”语句。

但是我不确定,我需要确认。如果是这样,是否有任何形式可以恢复这种使用?

谢谢。

2 个答案:

答案 0 :(得分:3)

您的WHILE的行为不像常规的while,因为在您的情况下,i<3是在通话时间一次进行评估的。 while语句每次都会对其进行评估。

如果您想写一个while等效项,那么您的条件应该是可以被评估的东西,而不是已经被 评估的东西,这一点很重要。

您可以通过接受Proc作为条件来解决此问题:

def so_long_as(cond)
  loop do
    return unless cond.call

    yield
  end
end

然后您这样称呼它:

i = 0
so_long_as(-> { i < 3 }) do
  print i
  i += 1
end

现在打印012并正确终止的位置。

要注意的重要一点是retry仅在begin / end上下文中有效,而不是常规方法,现在您必须改为使用redo:< / p>

i = 0
redone = false
so_long_as(-> { i < 3 }) do
  print i
  unless (redone)
    redone = true
    redo
  end
  i += 1
end

现在在哪里打印0012

some significant changes to how redo and retry work值得一读。

答案 1 :(得分:0)

恕我直言,使用 loop 有点违背给定练习的目标,因此我还有另外两个使用 redoretry 的解决方案,并且没有我想分享的循环。

如果您不知道我是怎么做的,我建议您在查看解决方案之前先尝试一下。

1. retry

def _while(cond, _loop=Class.new(RuntimeError))
  raise _loop if cond.call
rescue _loop
  yield
  retry
end

i = 0
_while(-> { i < 3 }) do
  print i
  i += 1
end

2. redo

def _while(cond)
  proc do
    if cond.call
      yield
      redo
    end
  end.call
end

i = 0
_while(-> { i < 3 }) do
  print i
  i += 1
end