如何在Ruby中打破外循环?

时间:2009-08-29 18:55:42

标签: ruby loops cycle

在Perl中,有能力打破这样的外循环:

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

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

8 个答案:

答案 0 :(得分:105)

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

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

答案 1 :(得分:36)

你想要的是非本地控制流,Ruby有几种选择:

  • Continuations,
  • 例外,
  • throw / catch

<强>延续

优点:

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

缺点:

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

<强>例外

优点:

  • 有一篇论文在数学上证明了Exceptions可以比Continuations更强大。 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社区比使用控制流的异常更讨厌它们。

答案 2 :(得分:29)

不,没有。

您的选择是:

  • 将循环放在一个方法中,并使用return to break from outer loop
  • 设置或返回内部循环中的一个标志,然后在外部循环中检查该标志,并在设置标志时断开它(这有点麻烦)
  • 使用throw / catch来打破循环

答案 3 :(得分:4)

while c1
 while c2
    do_break=true
 end
 next if do_break
end

或“如果do_break打破”,取决于你想要什么

答案 4 :(得分:2)

也许这就是你想要的? (未经测试)

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

find方法保持循环,直到该块返回非null值或者列表的末尾被命中。

答案 5 :(得分:0)

我知道我会在早上后悔,但只需使用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只是表达式变为true的一个示例。

答案 6 :(得分:0)

围绕循环包装内部方法可以解决问题 例如:

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

答案 7 :(得分:0)

您可以考虑添加一个在内循环内设置的标志,用于控制外循环。

&#39;下一个&#39;外循环

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

&#39;破&#39;外循环

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