Rubyでforやwhileでループ処理などを行なっているとき、条件によって途中でループ処理を抜ける時や、特定の条件では処理をスキップして、次のループ処理を行いたいことがあります。
この記事では、Rubyのループ処理に関する制御構文(break,next,redo)について解説します。
break,next,redoは制御構造
冒頭の通り、Rubyでループ処理の流れを制御するときは、break, next, redoの3つの制御構造を、用途に合わせて使用します。
breakは途中でループ処理を抜ける時、nextは処理をスキップして次のループを行う時、redoはループ処理をやり直したい時に使用する制御構造です。
continue相当の機能はnext
Rubyでは、ループ処理をスキップするときはnextを使用します。
もし、Javaなどの言語からRubyを学んでいる場合は、continueに相当するものは、Rubyではnextだと覚えておきましょう。
nextの使い方
最初は「next」制御構造について解説します。
ループ(繰り返し)処理の中でnextが呼ばれると、その時点で処理をスキップして次のループを行います。
配列の値や、特定の数値の時だけ処理をスキップする時などに使用します。
次のサンプルコードは、変数numが奇数の時だけ処理を行い、奇数の時はnextで処理をスキップする例です。
for num in 1..10 do
if num.even? then ## numが偶数か判定
next ## 処理をスキップし、次のループ処理を行う
end
p "num=%d" % num
end
【実行結果】
-----------------------------------
"num=1"
"num=3"
"num=5"
"num=7"
"num=9"
nextと条件(if)を合わせて1行で書く
上のサンプルコードでは、if文とnextを別々の行に記述しているが、break if 条件式のように1行でまとめて書くこともできます。
if文とnextを1行にまとめて記述すると、次のようにシンプルにコードが記述できます。
for num in 1..10 do
next if num.even?
p "num=%d" % num
end
breakの使い方
次に「break」制御構造について解説します。
ループ処理の中でbreakが呼ばれると、そこでループが終了しwhileやforなどのブロックから処理が抜け出します。
基本的には、ある条件に達した時にループを途中で抜ける用途などでbreakは使用します。
次のサンプルコードは、変数countを1ずつ加算し、5を超えた時点でbreakを実行し、ループ(while)を抜けるコードです。
count = 1
while true
if count > 5 then
break
end
p "%d回目の繰り返し" % count
count += 1
end
【実行結果】
-----------------------------------
"1回目の繰り返し"
"2回目の繰り返し"
"3回目の繰り返し"
"4回目の繰り返し"
"5回目の繰り返し"
breakと条件を合わせて1行で書く
上のサンプルコードでは、if文とbreakを別々に記述していましたが、break if 条件式のように1行でまとめて書くこともできます。
実際に、if文とbreakを1行にまとめたコードは次の通りです。
count = 1
while true
break if count > 5
p "%d回目の繰り返し" % count
count += 1
end
入れ子になったループの break
ループ処理が入れ子になった場合、breakによって抜けるのは、もっとも内側のループです。
実際にサンプルコードで試してみましょう。
for i in 1..2 do ## 外側のループ
for j in 1..10 do ## 入れ子になった内側のループ
break if j == 3
p "i=%d, j=%d" % [i, j]
end
p "内側のループを抜けました"
end
【実行結果】
-----------------------------------
"i=1, j=1"
"i=1, j=2"
"内側のループを抜けました"
"i=2, j=1"
"i=2, j=2"
"内側のループを抜けました"
入れ子になった内側のループで、break if j == 3の条件の時にループを抜けていますが、外側のループからは抜けていないため、再度、繰り返し処理が実行されています。
もし、入れ子になった内側のループをbreakで抜ける際に、合わせて外側のループも抜けるようにする場合は、次のコードのようにする必要があります。
## ループを脱出するためのフラグを用意
break_flg = false
for i in 1..2 do ## 外側のループ
for j in 1..10 do ## 入れ子になった内側のループ
if j == 3 then
break_flg = true ##ループ脱出フラグをtrueに設定
break
end
p "i=%d, j=%d" % [i, j]
end
## ループ脱出フラグがtrueの時、外側のループも抜ける
break if break_flg
end
【実行結果】
-----------------------------------
"i=1, j=1"
"i=1, j=2"
redoの使い方
最後に「redo」制御構造について解説します。
redoは、その時点で処理を中断し、繰り返し処理をも一度やり直したい時に使用します。
利用シーンがあまりなく、開発現場でも使用されることがない制御構造ですが、いざという時に知っておくと便利なので、使い方だけは覚えておきましょう。
では、次のサンプルコードをご覧ください。
こちらは、変数countが偶数の時はredOでもう一度ループ処理をやり直す処理となっています。
redo_flg = false
## countを1〜5まで繰り返し
for count in 1..5 do
p "count=%d" % count
## countの値が偶数で1回目の処理の時は、redoで処理をやり直し
## 偶数で2回目の処理の時は、redoは実行せずに次のループ処理を行う
if count.even? && !redo_flg then
redo_flg = true
redo
end
redo_flg = false
end
【実行結果】
-----------------------------------
"count=1"
"count=2"
"count=2"
"count=3"
"count=4"
"count=4"
"count=5"
countが偶数の時にredoを実行することにより、2回同じループカウントで処理が実行されているのが分かります。
next制御構造と動きは似ていますが、next制御構造は次のカウンタやイテレーターで処理を行うのに対し、redo`はループのカウントやイテレーターは次に進めず、ループ処理をやり直します。
まとめ
Rubyのbreak,next,redo制御構造を使って、ループ処理を制御する方法を解説してきました。
breakやnext使ってループ処理を中断・やり直しすることは多々あるため、使い方について是非覚えておきましょう。
— breakはループ処理を抜ける時に使用する
— nextは処理をスキップして次のループを行う時に使用する
— redoはループ処理をやり直したい時に使用する
【関連記事】
▶【Rubyの基礎】any?メソッドの使い方