こんにちは、かつコーチです。
「Rubyで繰り返し処理を書きたいけど、for・while・timesのどれを使えばいいのか分からない」。
他の言語の経験がある方ほど、こう迷うことが多いようです。
今回は、Rubyにおける繰り返し処理の書き方を一通り整理します。
読み終える頃には、それぞれの違いと使い分けが説明できるようになります。
繰り返し処理の基本の書き方
for文の書き方
まずは、他の言語でもおなじみのfor文からです。
for文は「配列や範囲の要素を順番に取り出しながら処理する」構文です。
for i in 1..5
puts i
end
1..5は範囲オブジェクト(Range)と呼ばれ、1から5までの連続した値を表します。
配列を対象にすることもできます。
fruits = ["りんご", "みかん", "ぶどう"]
for fruit in fruits
puts fruit
end
while文の書き方
while文は「条件が真である間、処理を繰り返す」構文です。
繰り返す回数があらかじめ決まっていない場合に向いています。
count = 0
while count < 5
puts count
count += 1
end
条件式(count < 5)がfalseになった時点でループが終了します。
条件を更新する処理(count += 1)を書き忘れると、無限ループになるので注意が必要です。
timesメソッドの書き方
timesメソッドは「決まった回数だけ処理を繰り返す」ためのメソッドです。
5.times do |i|
puts i
end
5.timesと書くだけで、0から4までの5回、ブロック内の処理が実行されます。
do |i| ... endの部分はブロックと呼ばれ、繰り返しのたびに実行されるコードのかたまりです。
|i|にはループの回数(0始まり)が渡されます。
loopメソッドとeachメソッドにも触れておく
Rubyにはほかにも、loopメソッドやeachメソッドがあります。
# loop:breakするまで無限に繰り返す
count = 0
loop do
break if count >= 5
puts count
count += 1
end
# each:配列の要素を1つずつ処理する
fruits = ["りんご", "みかん", "ぶどう"]
fruits.each do |fruit|
puts fruit
end
loopは無限ループを作り、breakで明示的に抜け出す場面で使います。
eachは配列やハッシュの要素を順番に処理したいときの定番メソッドです。
よくあるつまずきポイント・エラー対処
for文のスコープでハマる
Rubyのfor文は、実はブロック変数がループの外でも使えてしまうという特徴があります。
これは他の言語の感覚とズレやすいポイントです。
# ❌Before:for文の変数iはループの外でも生き残る
for i in 1..3
puts i
end
puts i # => 3(エラーにならず参照できてしまう)
私は最初にこの挙動を知らず、変数名の使い回しでバグを埋め込んだ経験があります。
iという変数をfor文の外の処理で別の意味で使い回してしまい、値が上書きされたことに気づかず数十分ハマりました。
# ✅After:eachを使えばブロックの外に変数が漏れない
(1..3).each do |i|
puts i
end
# ここでiを参照するとNameErrorになる(スコープが閉じている)
eachはブロック内だけで変数が有効なので、意図しない値の上書きを防げます。
timesで配列の値そのものが欲しくてハマる
timesは「回数」を渡すメソッドなので、配列の中身を直接取得することはできません。
# ❌Before:timesで配列の要素を取ろうとして詰まる
fruits = ["りんご", "みかん", "ぶどう"]
fruits.length.times do |fruit|
puts fruit # => 0, 1, 2(要素ではなくインデックスが表示される)
end
実行結果を見て「あれ、文字列が出るはずなのに数字が出る」と戸惑う方は多いです。
インデックスを使って配列にアクセスするか、素直にeachを使うのが解決策です。
# ✅After:インデックスで配列にアクセスする
fruits = ["りんご", "みかん", "ぶどう"]
fruits.length.times do |i|
puts fruits[i]
end
# もしくはeachを使う(こちらの方がシンプル)
fruits.each do |fruit|
puts fruit
end
なぜRubyではtimes・eachが好まれるのか
Rubyのコミュニティでは、for文よりもtimesやeachが好まれる傾向があります。
理由は主に2つです。
- for文は変数がループの外に漏れるため、意図しないバグの原因になりやすい
timesやeachは「何を繰り返すか」がメソッド名から一目で分かり、可読性が高い
実際に、Rubyの入門書や有名なOSSのコードを見ても、for文はほとんど登場しません。
繰り返し処理を書くときは、まずeachやtimesで書けないかを検討する、という習慣をつけておくとよいでしょう。
応用・一歩先の使い方
step・upto・downtoで細かい繰り返しを制御する
数値の繰り返しには、times以外にも便利なメソッドがあります。
# 2ずつ増やしながら1から10まで繰り返す
1.step(10, 2) do |i|
puts i
end
# 1から5まで昇順に繰り返す
1.upto(5) do |i|
puts i
end
# 5から1まで降順に繰り返す
5.downto(1) do |i|
puts i
end
「1つ飛ばしで処理したい」「逆順に処理したい」といった場面では、これらのメソッドを使うとfor文で条件式を自作するより簡潔に書けます。
next・breakで繰り返しの流れを制御する
繰り返しの途中で処理をスキップしたり、中断したりしたい場合は、nextとbreakを使います。
(1..10).each do |i|
next if i.even? # 偶数はスキップ
break if i > 7 # 7を超えたら中断
puts i
end
# => 1, 3, 5, 7
nextは「今回の処理だけスキップして次のループへ進む」、breakは「ループ自体をそこで終了する」という違いがあります。
この2つを使い分けられると、条件分岐を含む複雑な繰り返し処理もすっきり書けるようになります。
まとめ
この記事のポイント
- for文はシンプルだが、変数がループの外に漏れるため注意が必要
- while文は「繰り返す回数が決まっていない」場合に向いている
- timesは「決まった回数だけ繰り返す」場合に使う
- Rubyでは可読性と安全性の観点から、for文よりeach・timesが好まれる
- next・breakを使うと、繰り返しの流れを柔軟に制御できる
次に読むべき記事
次回は、配列を操作するmapとselectについて解説します。
「mapとselectで配列を操作する」を読んで、繰り返し処理をさらに応用してみましょう。