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

How does the retry statement work in Ruby?

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

手册在一个应该作为循环的方法中使用了 'retry' 关键字,但它没有使用 begin/rescue 块,当你强制 'retry' 关键字位于 begin/rescue 块内。

我试过很多东西: - 第一个是在方法的开头使用 "begin" 关键字,在重试点使用 'raise',然后是相应的 'rescue; retry; end;'。 -最后一个是在外面使用'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 块之前,它可能会以无法再使用的方式使用,重复调用 的方法,尽管 在该方法内部

现在,它只是跳转到 'begin' 语句。

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

谢谢。

您的 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 :

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 值得一读。

恕我直言,使用 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