57

在 Perl 中,可以像这样打破外部循环:

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

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

4

8 回答 8

107

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

catch (:done) do
  5.times { |i|
    5.times { |j|
      puts "#{i} #{j}"
      throw :done if i + j > 5
    }
  }
end
于 2009-08-29T19:02:25.207 回答
38

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

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

继续

优点:

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

缺点:

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

例外

优点:

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

缺点:

  • 它们被称为“例外”,这使人们认为它们“仅用于特殊情况”。这意味着三件事:阅读您的代码的人可能不理解它,实现可能没有针对它进行优化(而且,是的,几乎所有 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 社区讨厌它们,甚至比使用异常来控制流更讨厌。
于 2009-08-29T21:00:51.723 回答
32

不,没有。

您的选择是:

  • 将循环放在一个方法中并使用 return 从外部循环中中断
  • 从内部循环设置或返回一个标志,然后在外部循环中检查该标志并在设置标志时从它中断(这有点麻烦)
  • 使用 throw/catch 跳出循环
于 2009-08-29T19:00:36.567 回答
3
while c1
 while c2
    do_break=true
 end
 next if do_break
end

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

于 2012-09-29T10:21:53.200 回答
2

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

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

find 方法一直循环,直到块返回一个非空值或列表的末尾被命中。

于 2009-08-30T16:21:00.463 回答
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 循环中进行检查,并在满足条件后从内部方法返回。

于 2014-04-01T09:07:38.880 回答
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只是表达式变为真的一个例子。

于 2009-08-29T19:32:02.977 回答
0

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

'next' 外循环

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
于 2016-12-21T03:21:05.953 回答