Rubyのプログラムでも繰り返し処理にuntil構文が使えます。とはいえRubyの繰り返し処理でwhile構文やuntil構文を使う機会が少ないうえ、while構文だけで書けてしまうのえ、until構文をどこで使えばいいのかわからない、という方もいるかもしれません。
そこで今回はRubyのuntil構文の基本と、どういったケースでuntil構文を使えばよいかについて解説します。
Rubyにおける繰り返し処理
繰り返し処理はプログラミングの基本で、Rubyでは幾通りもの方法で繰り返し処理を記述することが可能です。中でも繰り返し処理を構文として、while、until、forの3つのステートメントが使われます。
なおRubyでは配列や範囲のようなオブジェクトに対してeachメソッドを使い、繰り返し処理と同じプログラムを作れます。そのため、他のプログラム言語ほどwhile、until、forの3つのステートメントが使われる機会が少ないかもしれません。
まずは今回紹介するuntilを繰り返し処理で使ううえでの基本的な考え方について紹介します。
シンプルな繰り返し処理ならwhileかuntil
多くのプログラム言語では、繰り返し処理を配列の操作の目的で使用します。しかし先ほど紹介したようにRubyには配列を操作する便利なメソッドがたくさんあることから、配列の操作でwhileやnutil、forが使われることはありません。
しかし、繰り返し処理は配列の操作だけで使われる訳ではありません。whileやuntilは、割り込みが入るまで処理を待機するケースなど、ある条件を満たすまで同じ処理を繰り返すシンプルな繰り返し処理でも使われます。Rubyでwhileやuntilを利用するなら、このようなシンプルな繰り返し処理で使われると考えてください。
配列を使う繰り返しはeachメソッド
配列は複数のデータを1つのまとめて扱えて繰り返し処理とも相性の良い変数です。しかしRubyで配列を操作するなら、eachメソッドなどの便利なメソッドがたくさんあります。そのため配列の操作にwhileやuntilの繰り返し処理を使うことはありません。
さらにPHPなどの他のプログラム言語ではファイルの読み込みなどでもwhile構文が使われますが、RubyではFileクラスのeachメソッドが使えます。そのためファイルの読み込みでもwhileやuntilによる繰り返し処理を使いません。
Rubyで繰り返し処理を作る場合は、まずはそのオブジェクトでeachメソッドなどが使えないかチェックしてください。eachメソッドを使うことで、読みやすくシンプルなプログラムを記述できます。
whileとuntilの使い分けは
条件を満たす間だけ繰り返すシンプルな繰り返し処理で使われるwhileとuntilの違いは、繰り返す条件がtrueかfalseかの違いです。whileは、引数で指定した条件がtrueの間、指定された処理を繰り返します。逆にuntilは、引数で指定した条件がfalseの間、指定された処理を繰り返します。
普段から英語を使わない方にとって、Rubyのwhileとuntilは条件が逆だけで同じものと思われるかもしれません。しかし、英語ではwhileとuntilはニュアンスが違います。whileは時の幅を表す言葉です。そのためプログラムでは「何かの処理が実行中の間、次の処理を繰り返す」といった使い方をします。
一方untilはある瞬間を表す言葉です。untilを使ったプログラムも「何等かのトリガーがあるまで、処理を繰り返す」という処理で使われます。英語の意味に合わせて使い分けてください。
until構文の基本
先ほど紹介したように、Rubyのuntil構文は条件がfalseからtrueになるまでの間、指定された処理を繰り返す処理を記述するための構文です。次からuntil構文の文法とその使い方を紹介します。
until構文の文法
制御構造を記述untilは、untilに続く式を評価し、その式がfalseの場合に続く処理を繰り返し、trueの場合に繰り返しを中断します。なお同じ繰り返し構文のwhileは、評価した式がtrueの場合に続く処理を繰り返し、falseの場合に繰り返しを中断するので、条件式が逆の関係です。
until構文の文法
until 条件式 [do]
繰り返す処理
end
「do」は省略可能です。
until構文の例
chk = false until chk do chk = check_interrupt() sleep 1 end
上の例は、check_interrupt()がfalseからtrueになるまで同じ処理を繰り返すプログラムです。
until構文の繰り返しはbreakで中断できる
until構文は、untilに続いて記述した繰り返し処理の途中で、breakを使うことで中断できます。また、breakは引数を指定することで戻り値を指定することが可能です。こうすることで、breakの引数をuntilの戻り値として利用できます。なお、breakの引数を省略した場合、untilの戻り値はnilです。
until構文をbreakで中断する記述方法
breakの戻り値 = until 条件式 do
処理1
if breakの条件式 break 戻り値
処理2
end
until構文をbreakで中断する例
answer = until false do ret = get_interrupt() if ret != nil then break ret end sleep 1 end
この例は、until false doで無限に繰り返す処理の中で、get_interrupt()の結果がnilでないなら、その結果をbreakで戻してuntilの戻り値として処理しています。
until構文は並列処理にも使われる
Rubyでは配列を操作する便利なメソッドが幾つもあり、また範囲やファイル操作もそれぞれのメソッドで操作できることから、今回紹介しているuntil構文の繰り返し処理はそのような処理では使われません。
Rubyのプログラムでwhileやuntilがよく使われるのが並列処理です。並列処理では、新しく作ったスレッドが終了した場合といった条件で次の処理を実行する、といったプログラムが使われます。そして、このような処理の記述に向いているのがuntil構文です。
並列処理で使われるuntil構文の例
q = Thread::Queue.new q.push(1) th = Thread.new do until q.empty? q.pop puts "execute" sleep 2 end end th.join
この例は、Thread::Queueの変数qが空になるまで実行するスレッドを生成するのに、until構文を使用した例です。
until修飾子を利用する
Rubyでは、until構文と同じような処理をuntil修飾子を利用して記述することが可能です。次からuntil修飾子についてその文法と使い方を紹介します。
until修飾子の文法
until修飾子は、untilの左側に記述した繰り返し処理を、右側の記述した条件式がfalseからtrueになるまで実行します。
until修飾子の文法
繰り返し処理 until 条件式
until修飾子を使った例
i = 0 puts i += 2 while i > 5
この例は「puts i += 2」の処理をuntilの右側の条件式「i > 5」がfalseの場合に繰り返します。なお、until修飾子の左側を先に実行した後、右側を評価するので、「i = 7」の状態を表示した後、繰り返しを中断するのでこの例では「3 5 7」の3つの数字を表示します。
until修飾子にbegin~endを適用する
先ほど紹介したuntil修飾子で最初から条件が合わない場合は、繰り返し処理が全く処理されません。条件に合わなくても1回だけ繰り返し処理を実行するには、until修飾子にbegin~endを適用してください。
例えば下記のように最初から条件に合わない場合は処理されません。
i = 10 puts i -= 2 until i < 11
しかし、下記のようにbegin~endを適用することで条件に合わなくても1回だけ処理されます。
i = 10 begin puts i -= 2 end until i < 11
上の例では、untilの条件に合わないものの、「8」が表示されます。
まとめ
今回紹介したようにRubyにはある条件なら処理を繰り返すwhile構文とuntil構文があり、while構文では真の条件で、until構文は偽の条件で繰り返します。英語のuntilは「~になるまで」という意味なので、条件が真になるまで繰り返す処理に使ってください。
さらに簡単な処理であればuntil修飾子も使えて、同じように真になるまで繰り返す処理をシンプルに記述できます。なおRuyでは繰り返し処理を記述する方法が幾つもあり、until構文を使う機会はそれほど多くありません。並列処理など、どうしてもuntilが必要なケースで利用してください。