はじめに
こんにちは、絶賛Ruby勉強中のものです。
本日はRubyで出てくる繰り返し文について簡単にまとめようと思い記事にしました。
繰り返すという点では同じですが、それぞれ違う用途で使われることが多くわからなくなってしまうことがあると思うので初心者向けではありますが見ていきたいと思います
Rubyの繰り返し文
まずはRubyの繰り返し文とひとくくりにしていますが、制御構文とメソッドにその性質をもつものがあります。
制御構文はif
とかuntil
、case
などのことを言います。なので本来は一緒に紹介するものではないのですが、繰り返すというグループで囲むと同じなのでまとめて紹介していきます。
- times(メソッド)
- for(制御構文)
- while(制御構文)
- until(制御構文)
- each(メソッド)
- loop(メソッド)
times
times
は「○回繰り返す」と決まっている場合に便利な構文です。
例えば、5.timesとすると5回だけ処理を繰り返します。
5.times do |i|
puts i
end
# 0
# 1
# 2
# 3
# 4
また、do ... endの代わりに中括弧 { ... }を使って以下のように短く記述することも可能です。
5.times { |i| puts i }
for
ruby以外のほかの言語の繰り返しといえばfor
を連想しますよね。
for
は配列や範囲のすべての要素に対して繰り返し処理をしたいときに使用されます。
sum = 0
for i in 1..3
sum += i
end
puts sum
# 6
Rubyのfo
r文は、すべての要素を繰り返し処理する時に便利ですが、Rubyでは一般的にeach
の方がよく使われます。
理由の一つは、for
はループの外でも変数が参照できてしまうためです。
# forの場合
for i in (1..3)
puts i
end
puts i # forではループ外でも変数iが使える
# eachの場合
(1..3).each do |j|
puts j
end
puts j # eachではエラーが出る
each
はブロックを使用しており、スコープが限定されるため、ループ外で変数が参照できません。
このことで思わぬ副作用を防ぎ、コードの安全性が向上します。
while
条件が真である限り繰り返しを行いたい場合に使用されます。
total = 0
i = 1
while i <= 5
total += i
i += 1
end
puts total
# 15
上記のように5回繰り返す場合、for
やtimes
でも同じ結果を得られますが、条件を自由に設定できる点がwhile
の特徴です。
例えば、以下のように合計が50に達するまで処理を繰り返す場合などはwhile
が適しています。
total = 0
i = 1
while total < 50
total += i
i += 1
end
puts total
whileの追記
コメントで教えていただいたのですが、実はwhile
はあまり出番がないようです!
教材ベースで学んでおいてこういった気づきがあるのも面白いですね。
では具体的にどういうことが説明してきます。while2.rb
のコードについてみていきましょう
total = 0
1.step do
total += _1
break if total >= 50
end
puts total
行数では 1 行しか減っていませんが,「i の値を初期化する」「i の値を 1 ずつ増やす」という処理をいちいち書かなてくよいぶん,把握しやすいように思います。
(Numeric#step は初期値に増分と上限・下限を与えて繰り返すイテレーターです。ここでは増分〔既定値 1〕を略し,上限を無しとして使っています)
上記のようにコメントをいただきました。
step
というメソッドは初めて知ったのですが、while
よりも冗長すぎなくて見やすいコードになりますね。
そう考えるとwhile
の出番ってほんとに少ないのかもしれません。
until
条件が「偽」になるまで繰り返したい場合に使用します。
if
にもunless
という条件が偽の場合に処理を行う条件式がありましたが、until
はwhile
の逆バージョンと思っていただければ大丈夫です
total = 0
i = 1
unless total >= 50
total += i
i += 1
end
puts total
これはwhile2.rb
をunless
に書き直したコードです。while
とは条件式が逆になっています
each
Rubyではfor
の代わりに、配列や範囲オブジェクトに対する繰り返し処理にはeach
が多く使用されます。
for
に比べてスコープが狭くなり、思わぬ副作用を防ぐことができるためです。
sum = 0
(1..3).each do |i|
sum += 1
end
puts sum
loop(追記)
こちらもコメントいただいたので追記です。
loopは無限ループ作るときくらいしか使わないと習ったのですが、while
の代わりに使う場面があるようです。
繰り返し処理の典型的なパターンの一つに以下のようなものがあります。
- 処理 A を行う
- その結果次第でループを抜ける
- 抜けなかった場合は処理 B を行う
- 以上を繰り返す
ここで,処理 A が非常に単純なとき,while で書けます:
while [処理 A とその結果による条件式]
処理 B
end
しかし,[処理 A とその結果による条件式] が単純な式で書けない場合,非常に見づらいコードになります。
こういうときはloop
メソッドを使って
loop do
処理 A
break if 条件式
処理 B
end
と書くのがよい場合があります。
loop
は無限ループのみしか使わない、いわばのけものと扱わずにこんなにスマートな使い方があることを教えていただきました。
他にもloop
の使い方を知っている方は教えていただけると励みになります。
まとめ
Rubyの繰り返し文には、それぞれ独自の特徴と適した場面があります。
- 固定回数の繰り返しには
time
s - 配列や範囲オブジェクトの要素に対して繰り返しを行うには
each
- 自由な条件に基づく繰り返しが必要なら
while
やuntil
。ただし、while
はeach
やloop
にとってかわられることが多く使う機会がない - スコープを意識せず使いやすいが、制御が必要な場合は
for
よりもeach
が推奨されます