如何打破Ruby中的外循环?

问题描述 投票:0回答:9

在 Perl 中,有一种打破外循环的能力,如下所示:

AAA: for my $stuff (@otherstuff) {
         for my $foo (@bar) {
             last AAA if (somethingbad());
         }
      }

(语法可能错误),它使用循环标签将外循环从内循环内部断开。 Ruby 有类似的东西吗?

ruby loops cycle
9个回答
111
投票

考虑

throw
/
catch
。通常,下面代码中的外部循环将运行五次,但使用 throw 您可以将其更改为您喜欢的任何内容,并在过程中中断它。考虑这个完全有效的 ruby 代码:

catch (:done) do
  5.times { |i|
    5.times { |j|
      puts "#{i} #{j}"
      throw :done if i + j > 5
    }
  }
end

39
投票

你想要的是非本地控制流,Ruby 有几个选项可以做到这一点:

  • 继续,
  • 例外情况,以及
  • throw
    /
    catch

继续

优点:

  • Continuations 是非局部控制流的标准机制。事实上,您可以在它们之上构建 any 非本地控制流(子例程、过程、函数、方法、协程、状态机、生成器、条件、异常):它们几乎是
    GOTO 的更好双胞胎
    .

缺点:

  • Continuations 不是 Ruby 语言规范的强制部分,这意味着某些实现(XRuby、JRuby、Ruby.NET、IronRuby)不实现它们。所以,你不能依赖他们。

例外情况

优点:

  • 有一篇论文从数学上证明了异常可以比延续更强大。 IOW:它们可以完成延续可以做的所有事情,甚至更多,因此您可以使用它们作为延续的替代品。
  • 例外情况普遍存在。

缺点:

  • 它们被称为“例外”,这让人们认为它们“只针对特殊情况”。这意味着三件事:读你代码的人可能不理解它,实现可能没有针对它进行优化(是的,在几乎所有 Ruby 实现中,异常都非常慢),最糟糕的是,你会厌倦所有这些这些人一看到你的代码,就不断地、无意识地胡言乱语“例外只是在特殊情况下”。 (当然,他们甚至不会尝试理解你在做什么。)

throw/

catch


这(大致)是这样的:

catch :aaa do stuff.each do |otherstuff| foo.each do |bar| throw :aaa if somethingbad end end end

优点:

与异常相同。
  • 在 Ruby 1.9 中,使用控制流异常实际上是
  • 语言规范的一部分
  • !循环、枚举器、迭代器等都使用 StopIteration 异常来终止。
    
    
    
  • 缺点:

Ruby 社区对它们的憎恨甚至超过了对控制流使用异常的憎恨。

32
投票

您的选择是:

将循环放入方法中并使用 return 来从外循环中中断
  • 从内循环中设置或返回一个标志,然后在外循环中检查该标志,并在设置该标志时中断它(这有点麻烦)
  • 使用 throw/catch 来跳出循环

3
投票
或“break if do_break”取决于你想要什么


2
投票

stuff.find do |otherstuff| foo.find do somethingbad() && AAA end end

find 方法不断循环,直到块返回非空值或到达列表末尾。


1
投票

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 循环内进行检查,并在满足条件后从内部方法返回。


0
投票

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

只是表达式变为 true 的一个示例。

    


0
投票

“下一个”外循环

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



0
投票

© www.soinside.com 2019 - 2024. All rights reserved.