ループ(繰り返し)

Rubyに慣れてくると each{} ばっかり使っているような気がしますが、とりあえず1回実行して後で評価する、Cでいうところの do {} while を使いたいときもたまにあります。そういうときのためのメモ。

まず、ループのまとめ

  • for 文
    for 変数 in オブジェクト do 繰り返し処理 end
    例) sum=0; for i in 1..100 do sum+=i end; p sum
    forは文なので、do end を { } に替えることはできません。

  • while 文
    while 条件 do 繰り返し処理 end
    例) sum=i=0; while i<100 do i+=1; sum+= i end; p sum
    whileは文なので、do end を { } に替えることはできません。

  • until 文
    until 否定条件 do 繰り返し処理 end
    例) sum=i=0; until i>=100 do i+=1; sum+= i end; p sum
    untilは文なので、do end を { } に替えることはできません。

  • each メソッド
    オブジェクト.each do |変数| 繰り返し処理 end
    例) sum=0; (1..100).each{|i| sum+=i}; p sum
    メソッドの繰り返しは do end でも { } でもOK。

  • loop メソッド
    loop { 繰り返し処理 }
    例) sum=i=0; loop{i+=1; sum+=i; if i>=100 then break end}; p sum
    do end でも { } でもOK。

  • times メソッド
    回数.times do 繰り返し処理 end
    例) sum=0; 100.times{|i| sum+=i+1}; p sum
    |変数|は 0から ++されるのでこういう書き方でOK。

  • その他メソッド(upto, downto, step)
    回数.メソッド do 繰り返し処理 end
    例) sum=0; 1.upto(100){|i| sum+=i}; p sum
    |変数|は「始まり」から「終わり」まで ++される。

  • その他メソッド(each_with_indexなど)
    オブジェクト.メソッド do |変数| 繰り返し処理 end
    例) sum=0; (1..100).each_with_index{|v,i| sum+=v}; p sum
    この例は単に eachでいいけれど、普通はブロックのなかで indexが欲しいときに使う。

で、とりあえず1回実行して後で評価の繰り返し

sum = i = 0
begin
  i   += 1
  sum += i
# if i >= 100
#   break sum
# end
end while i < 100
p sum

この例だとありがたみがありませんが、とにかく begin 繰り返し処理 end while 条件 と書けるよということです。
あと、この例ではコメントにしてありますが、break に引数を持たせることができ、それがブロック(begin end)の戻り値になります。break なしで while条件で抜けだしたときのブロックは nil を返します。
ここで使っている while は、while 修飾子といって「式1 where 式2」と書くと、式2が Trueの間、式1を実行します。これを使うと上の sumを計算する例はこういうふうに書けます。2番目はすぐ上の例です。

  • 例) sum=i=0; sum+=i while (i+=1)<=100; p sum
  • 例) sum=i=0; begin i+=1; sum+=i end while i<100; p sum

loop と while true の違い

制御構造であるwhileとイテレータであるloopの間の本質的な違いはloopの方はループ本体がブロックである点です。そしてブロックは新たなスコープを導入します。

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/20222

これの意味がちっともわからなかったんですが、こちら(→http://www.pshared.net/diary/20071211.html#p01)を見てやっと腑に落ちました。loop内で定義された変数は loopを抜け出すとなくなりますよ、while内で定義された変数は whileを抜け出してもそのまま有効ですよという意味ですね。ということは、while、for、until は繰り返しを抜け出しても有効、その他の繰り返しメソッドは繰り返し内のみ有効ということですか。

参考

  1. Rubyのリファレンスマニュアルといえば、こちら(→プログラミング言語 Ruby リファレンスマニュアル)。制御構造のところです。
  2. loopとwhile trueの違いは、こちら(→http://www.pshared.net/diary/20071211.html#p01)がわかりやすかったです。