如何打破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实际上是语言规范的一部分 ! 循环,枚举器,迭代器等都使用StopIterationexception来终止。

缺点:

  • 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