3

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

该手册在应该充当循环的方法中使用了“重试”关键字,但它在没有开始/救援块的情况下使用,当您强制“重试”关键字位于开始时,行为似乎完全不同/救援块。

我尝试了很多事情: - 第一个是在方法开始时使用“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 (加上一个明显的无限循环打印什么)

我希望你能把我从这个存在的怀疑中解脱出来,但这是我的结论。

在强制使用“重试”关键字的开始/救援块之前,它可以以一种不能再使用的方式使用,重复调用一个方法,尽管它位于该方法的内部

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

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

谢谢。

4

2 回答 2

4

你的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

值得一读的方式工作方式发生了一些重大变化。redoretry

于 2019-05-08T16:41:15.127 回答
0

恕我直言,使用loop有点失败了给定练习的目标,因此我有两个其他解决方案使用redoorretry并且没有我想分享的循环。

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

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
于 2021-05-07T14:13:45.630 回答