如何打破Ruby的外部循环?
在Perl中,可以像这样打破外部循环:
AAA: for my $stuff (@otherstuff) { for my $foo (@bar) { last AAA if (somethingbad()); } }
(语法可能是错误的),它使用循环标签来打破内部循环内部的外部循环。 Ruby中有类似的东西吗?
你想要的是非本地控制stream,Ruby有几种select:
- 延续,
- 例外,和
-
throw
/catch
延续
优点:
- 延续是非本地控制stream程的标准机制。 事实上,你可以build立任何非本地的控制stream(子例程,程序,函数,方法,协程,状态机,生成器,条件,例外):它们几乎是
GOTO
的更好的孪生GOTO
。
缺点:
- 继续不是Ruby语言规范的强制性部分,这意味着某些实现(XRuby,JRuby,Ruby.NET,IronRuby)不实现它们。 所以,你不能依靠他们。
例外
优点:
- 有一篇论文从math上certificateexception可能比Continuations更强大。 IOW:他们可以做所有延续可以做的事情,还有更多,所以你可以用它们作为延续的替代品。
- 例外是普遍可用的。
缺点:
- 他们被称为“例外”,这使得人们认为他们只是“特殊的情况下”。 这意味着三件事情:有人读你的代码可能不理解它,实现可能没有被优化(是的,几乎所有的Ruby实现中,exception都是缓慢的),最糟糕的是,你会厌倦所有这些人不断地,无意识地喋喋不休地说“只有特殊情况下的例外”,只要他们看一下你的代码。 (当然,他们甚至不会理解你在做什么。)
throw
/ catch
这(大体上)是这样的:
catch :aaa do stuff.each do |otherstuff| foo.each do |bar| throw :aaa if somethingbad end end end
优点:
- 与例外相同。
- 在Ruby 1.9中,使用控制stream的exception实际上是语言规范的一部分 ! 循环,枚举器,迭代器等都使用
StopIteration
exception来终止。
缺点:
- Ruby社区更讨厌他们比使用控制stream的exception更多。
考虑throw
/ catch
。 通常情况下,下面的代码中的外部循环将运行五次,但是使用throw可以将其更改为任何您喜欢的内容,并在此过程中将其分解。 考虑这个完全有效的ruby代码:
catch (:done) do 5.times { |i| 5.times { |j| puts "#{i} #{j}" throw :done if i + j > 5 } } end
不,没有。
您的select是:
- 把循环放在一个方法中,并使用return从外部循环中断
- 设置或从内部循环返回一个标志,然后检查外部循环中的标志,并在设置标志时从中断开(这很麻烦)
- 使用throw / catch打破循环
while c1 while c2 do_break=true end next if do_break end
或“如果do_break”,取决于你想要什么
也许这是你想要的? (未testing)
stuff.find do |otherstuff| foo.find do somethingbad() && AAA end end
find方法保持循环,直到块返回一个非空值或列表的结尾被命中。
我知道我会在今天早上后悔,但只是使用一个while循环可以做到这一点。
x=0 until x==10 x+=1 y=0 until y==10 y+=1 if y==5 && x==3 x,y=10,10 end end break if x==10 puts x end
if y==5 && x==3
只是expression式转换为真的一个例子。
在循环中包装一个内部方法可以做到这一点例子:
test = [1,2,3] test.each do |num| def internalHelper for i in 0..3 for j in 0..3 puts "this should happen only 3 times" if true return end end end end internalHelper end
在这里,您可以在任何for循环中进行检查,并在条件满足时从内部方法返回。
您可以考虑在内部循环中添加一个标志来控制外部循环。
接下来是外部循环
for i in (1 .. 5) next_outer_loop = false for j in (1 .. 5) if j > i next_outer_loop = true if j % 2 == 0 break end puts "i: #{i}, j: #{j}" end print "i: #{i} " if next_outer_loop puts "with 'next'" next end puts "withOUT 'next'" end
“打破”外部循环
for i in (1 .. 5) break_outer_loop = false for j in (1 .. 5) if j > i break_outer_loop = true if i > 3 break end puts "i: #{i}, j: #{j}" end break if break_outer_loop puts "i: #{i}" end