57

Perl には、次のように外側のサイクルを壊す機能があります。

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

(構文が間違っている可能性があります)。ループ ラベルを使用して、外側のループを内側のループから切り離します。Rubyに似たようなものはありますか?

4

8 に答える 8

107

throw/catchを検討してください。通常、以下のコードの外側のループは 5 回実行されますが、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: 継続でできることはすべてできるので、継続の代わりとして使用できます。
  • 例外はどこでも利用できます。

短所:

  • それらは「例外」と呼ばれ、人々に「例外的な状況のためだけ」と思わせます。これは 3 つのことを意味します: あなたのコードを読んでいる誰かがそれを理解していない可能性があること、実装が最適化されていない可能性があること (そして、ほとんどすべての 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

必要に応じて、または「do_breakの場合はブレーク」

于 2012-09-29T10:21:53.200 に答える
2

おそらくこれはあなたが望むものですか?(未検証)

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

find メソッドは、ブロックが null 以外の値を返すか、リストの最後に到達するまでループし続けます。

于 2009-08-30T16:21:00.463 に答える
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 に答える