【Ruby】while文とは?基本構文から実用例までわかりやすく解説
はじめに
皆さんは、Rubyのプログラムを組むときに、繰り返し処理をどのように書くでしょうか。
Rubyにはさまざまな方法がありますが、そのなかでもシンプルで使いやすいものとしてwhile文が挙げられます。
たとえばリストの中身を繰り返し処理したいときや、特定の条件が満たされるまでずっと繰り返したいときに便利です。
ただし、上手に使わないと意図せず無限ループになってしまったり、思わぬところで処理が止まらなくなったりすることもあります。
今回の記事では、繰り返し処理の基本としてのwhile文の書き方を中心に、具体的な構文例や実務での活用シーンをくわしく解説していきます。
Rubyでのプログラミングが初めての方でも理解しやすいように、専門用語はできるだけ平易な言葉で紹介しますので、ぜひ最後まで読んでみてください。
この記事を読むとわかること
- while文の基本構文と、よく使う制御フローの書き方
- breakやnext、redoなどの利用シーン
- 他のループ構文 (for, until, each など) との違い
- 無限ループを避けるための注意点や実務での活用事例
- トラブルシューティングのポイントとデバッグ方法
ここで取り上げる内容を押さえることで、Rubyのwhile文を使った実装がぐっとわかりやすくなるでしょう。
while文とは?
Rubyにおけるwhile文は、**「条件が真である間、繰り返し処理を実行し続ける」**という構文です。
他のプログラミング言語にも同様のwhile文がありますが、Rubyらしいシンプルな文法のおかげで、比較的読みやすいコードを書きやすいのが特徴です。
どのような場面で使われるか
実務のシーンをイメージすると、バッチ処理や簡易的なデータ取得処理、あるいはユーザーからの入力を受け付けるループなど、**「特定の状態が続く限り動作させたい」**といった場面が多いです。
たとえば、在庫数が一定以上ある間は処理を繰り返すとか、センサーからのデータを常に監視して一定の範囲を超えたらループを終了するといったケースなどが考えられます。
また、GUIアプリケーションでメインループを組む、あるいはサーバーがリクエストを受け続ける状態を作るといったときにも利用されることがあります。
ただし、こうしたシステムレベルのループはフレームワーク側がすでに整備していることも多いので、実際には自分で記述する機会が少ないかもしれません。
それでも、Rubyのスクリプトを自作して何らかの自動処理を行いたい場合には、while文を活用する可能性が大いにあります。
基本的な構文
Rubyのwhile文は、下記のような書き方が基本形です。
while 条件式 # 条件式が真の間、繰り返したい処理 end
条件式には、真偽値を返す式を記述します。
たとえばi < 5
やstatus == "running"
のように書くイメージです。
この構文で注意したいのは、条件式を正しく更新していかないと、ループが永遠に終わらなくなる可能性があることです。
たとえばi = 0
のままループを回して、内部でi
を1ずつインクリメント(加算)しないとi < 5
はずっと真になってしまいます。
while文の書き方の実例
ここでは、より具体的にwhile文をどのように使うのかを見てみましょう。
Rubyでプログラミングを始めたばかりの方にもわかるよう、段階を踏んでサンプルコードを紹介していきます。
条件付き繰り返し処理の流れ
まず、シンプルな例からです。
i
が5より小さい間、繰り返しを行うコードを示します。
i = 0 while i < 5 puts "現在の値: #{i}" i += 1 end
- 変数
i
を0で初期化します。 while i < 5
で、i
が5より小さい場合にのみ内部の処理を繰り返すように設定しています。puts
で出力したあと、i += 1
でi
を1ずつ加算していきます。
もしここでi += 1
の行を忘れてしまうと、i
はずっと0のままでi < 5
が永遠に真となり、ループが終わらなくなってしまうでしょう。
このように、while文を使うときは、ループの制御に使う変数や条件式の状態を適切に更新することがとても大切です。
breakを使った終了方法
Rubyには、繰り返し処理を途中で強制的に終了するためのbreakというキーワードがあります。
while文を使う上で覚えておくと便利なので、次の例を見てみましょう。
count = 0 while true count += 1 puts "処理回数: #{count}" # ある条件に達したらループを抜ける if count >= 3 break end end
- 条件式に
true
と書くことで、もともとは無限ループ(終わらないループ)となっています。 - 内部で
count
をインクリメントし、count >= 3
となったタイミングでbreak
しています。
このパターンは、ループを開始する時点では終了条件が明確に定まっていないが、ループ中で判定する必要がある場合などに便利です。
とはいえ、無限ループは誤用すると危険ですので、必ず終了条件をしっかり設計するようにしましょう。
nextを使ったスキップ処理
処理を途中で抜けるbreak
とは別に、nextというキーワードでその時点の繰り返し処理をスキップして次の反復に移ることができます。
i = 0 while i < 10 i += 1 # 偶数はスキップ if i.even? next end puts "奇数だけを処理: #{i}" end
この例では、i
が偶数の場合にはnext
で処理をスキップしています。
そのため出力には奇数だけが表示されるという動作になります。
redoを使ったやり直し
もうひとつ、ループ処理中の同じ反復を再度やり直したいときには、redoを使うことができます。
たとえばユーザーからの入力が正しい形式ではなかった場合に、同じ繰り返しを再度試すときなどに用いられます。
attempt = 0 max_attempts = 3 while attempt < max_attempts puts "何か文字を入力してください。" input = gets.chomp # 標準入力から文字を取得 if input == "" puts "入力が空です。やり直します。" redo end puts "入力を受け取りました: #{input}" attempt += 1 end
もしここでinput
が空文字だったときには、redo
によって同じ繰り返しをもう一度行います。
attempt
はインクリメントされませんので、実質的に同じ繰り返しのやり直しになるわけです。
ただし、redo
は使い方を誤るとループが延々続く可能性があるため、使用時は注意が必要です。
while文と他のループ構文の比較
Rubyでは、繰り返し処理を実現する方法が複数用意されています。
while文に慣れた方は多いでしょうが、他の選択肢も一緒に覚えておくと便利です。
ここでは、ほかの代表的な繰り返し構文としてfor文、until文、eachメソッドを簡単に比較してみます。
while文とfor文の使い分け
Rubyのfor
は、以下のような形で要素を取り出す場合によく使います。
for num in [1, 2, 3, 4, 5] puts "値: #{num}" end
一方でRuby界隈では、for
よりもeachメソッド
を使うことが多いです。
for
はブロック変数のスコープなどがやや特殊なこともあり、イテレーションを行う場合、Rubyプログラマーは通常array.each do |num| ... end
という書き方を好みます。
while
は主に**「条件式が成立している間はずっと実行」**というイメージが強く、開始時点で繰り返す要素が明確に決まっていない場合に適しています。
実務では「いつまで続くかは動的に変わるが、特定のフラグが偽になるまで続けたい」というケースに向いています。
until文との違い
while
が「条件式が真の間、処理を繰り返す」なのに対し、until
は「条件式が偽の間、処理を繰り返す」というものです。
つまり、while i < 5
と until i >= 5
は同じ動作になる、とよく言われます。
ただし、コードの可読性を考えたときに、「この繰り返しはまだ条件に達していない間続く」というニュアンスを表現したいならuntil
がわかりやすいときもあります。
一方でwhile
のほうが慣れている、という方も多いですし、これは好みや社内のコーディング規約に従うといった場合が多いでしょう。
eachメソッドとの違い
配列やハッシュなど、あらかじめ繰り返す要素がはっきりしている場合は、eachメソッド
が使われることが多いです。
Rubyではイテレーションに関してはeach
のほうが直感的に書けるので、要素の走査や列挙をする際にはwhile
やfor
よりもeach
のほうが主流とされています。
たとえば、以下のような単純な繰り返しはeach
で書いたほうが読みやすいことが多いです。
numbers = [1, 2, 3, 4, 5] numbers.each do |num| puts "配列の要素: #{num}" end
while
の場合は条件式を用意しなければならないため、配列の添字を0から順番にインクリメントして...というコードを書きがちです。
しかしRubyなら、each
で要素を取り出すほうが自然と言えるでしょう。
無限ループを扱う場合の注意点
while文を使うときに気をつけたいのは、無限ループを引き起こすリスクです。
無限ループ自体は、先ほどのwhile true ... end
のように意図して書くこともありますが、意図せず発生すると大きな問題になります。
exit条件やbreakの活用
無限ループを組むときには、プログラム内部で「抜けるタイミング」を制御する仕組みが絶対に必要です。
具体的には、if
文で判定をしてbreak
するパターンが一般的です。
一方で、外部からのイベントやユーザー入力をきっかけに終了する場合もあるため、その場合はフラグをセットしてあげるなど、どこかでループ終了の合図を受け取る設計を行う必要があります。
また、実務で監視プログラムやバッチ処理を無限ループで実装する際は、一定の間隔を置いてループを実行するようにしないと、CPUの無駄遣いやリソース使用量の急増を招くかもしれません。
適度にsleep
を入れたり、イベントドリブンな仕組みを活用したりといった工夫が必要です。
実行タイミングとCPU負荷に気をつける
無限ループが走り続けると、コンピューターが常に処理をしようとし続けてしまう可能性があります。
特に、ループ内で重い計算をしていると、CPUに大きな負荷がかかり、他の処理が遅くなることもあるでしょう。
開発段階でやりたい処理をすぐに試すために「とりあえず無限ループで動かす」とすると、テスト環境や開発用マシンが必要以上に負荷を受け、動作が鈍くなったりすることがあります。
本番稼働環境で同じことをやると、サービスが不安定になる場合もあるため、実務で無限ループを使うときは十分な確認が重要です。
無限ループの設計をするときには、終了条件を必ず明確にしておきましょう。 終了させない場合でも、CPU負荷を下げるためにタイマーやイベント待ちの仕組みを取り入れるなどの対策が欠かせません。
実務での利用例
ここでは、while文を実務にどう結びつけるかを考えてみます。
Rubyのスクリプトとして簡易的に処理を自動化したい場合など、いろいろな場面で利用される可能性があります。
バッチ処理での使い方
企業でのシステム開発において、定期的にデータを集計するバッチ処理を組むことがあります。
たとえば「在庫情報を一定のサイクルで確認し、在庫数が減ってきたら補充処理を走らせる」などのケースです。
def check_stock # 在庫数を取得する処理を想定 10 # 仮に在庫数が10個あったとする end stock_threshold = 5 while true stock = check_stock puts "現在の在庫数: #{stock}" if stock < stock_threshold puts "在庫が少なくなりました。補充処理を実行します。" # 補充処理の呼び出しなどを実装 # breakするかどうかはケースバイケース end # 一定時間待機してから再度チェック sleep 60 # 1分間隔で在庫チェック end
このようなサンプルでは無限ループを使っていますが、一定の間隔を置いてcheck_stock
を呼び出す処理になっています。
ただし、実務ではバッチ処理の終了タイミングやログの扱いなどをきちんと設計する必要があります。
もし在庫管理の時間帯やシステムメンテナンスのスケジュールが決まっているなら、指定された時刻を過ぎたらbreak
を入れるなどの工夫をすればトラブルを避けやすいです。
ユーザーの入力受付
シェルスクリプト感覚でRubyを使う場合など、ユーザーが特定のコマンドを入力するまで処理を繰り返すというケースがあります。
while true puts "コマンドを入力してください(exitで終了)" cmd = gets.chomp if cmd == "exit" puts "終了します。" break end puts "入力されたコマンド: #{cmd}" # 実際はここで処理を分岐したりする end
この例では、exit
と入力されたらループを抜けるようにしています。
Rubyの実行環境があれば簡単に作れるので、小さなツールを自作する際に便利です。
リソース監視
サーバーのCPU使用率やメモリ使用量をチェックし、一定の閾値を超えたら通知を送るというプログラムをwhile文で作ることもあります。
シンプルな構成であれば、下記のような雰囲気になるでしょう。
def get_cpu_usage # CPU使用率を取得する処理を想定 50 # 仮に50%とする end threshold = 80 while true usage = get_cpu_usage puts "CPU使用率: #{usage}%" if usage > threshold puts "CPU使用率が高いです。警告通知を送信します。" # 実際に通知する処理などを挟む # 必要に応じてループを終了させるかどうか判断 end sleep 30 end
無限ループで定期的に監視を行うことで、アラートを出すようにできます。
実際には監視ツールやクラウドサービスが提供している仕組みに乗ることが多いですが、あえてカスタムスクリプトを書くときは、このようなwhile文が基本になるでしょう。
トラブルシューティングとデバッグ
while文を使った繰り返し処理でバグが起きた場合、プログラムが止まらなくなる、あるいは途中で意図せず終了してしまうなどのトラブルがよく見られます。
ここでは、そのようなときにどう対処するか、よくあるポイントを確認しましょう。
ログの活用
もしループ処理で何が起きているか分からなくなったときは、途中経過をログに残すのがおすすめです。
出力先としては標準出力で見てもいいですが、テキストファイルに書き出すようにしておくと、後から分析しやすいかもしれません。
File.open("loop.log", "a") do |f| count = 0 while count < 5 f.puts("ループカウント: #{count}") count += 1 end end
このようにしておくと、ループがどのようなタイミングで繰り返されているのかがわかりやすくなるため、予想外の挙動が起こったときに原因を特定しやすくなります。
条件式の見直し
多くのケースで問題になるのは、条件式にバグがある場合です。
たとえば本来はwhile i < 10
とすべきところをwhile i <= 10
にしてしまい、ずっとループが続いてしまうことがあったりします。
また、文字列の比較で大文字・小文字が合わないだけでも、思ったとおりにループが抜けられなくなるかもしれません。
もし意図せずループが終わらない(あるいは逆に早々に終わってしまう)ときは、次の点をチェックしてみてください。
- 条件式が正しく更新されているか
- 比較演算子は合っているか(
<
と<=
の混同など) - 変数やフラグが思わぬタイミングで変更されていないか
- breakやnextなどのタイミングは適切か
ここで提示したポイントを踏まえてコードを見直すだけで、バグの原因が見つかることは多いです。
特に、複数のwhile文を入れ子で使っている場合、どのループがどの変数を制御しているのか混乱しやすいです。
各ループで使う変数名を工夫したり、適宜メソッドに切り出すなど、整理して書くとバグを減らせます。
まとめ
ここまで、Rubyのwhile文について解説しました。
while文は「条件が真のあいだずっと繰り返す」というシンプルな仕組みですが、実際にはbreak
やnext
、redo
といった制御フローと組み合わせることで、多彩な処理を記述できます。
- while文は特定の条件が成り立つあいだ、同じ処理を繰り返したいときに便利
- 変数の値を適切に更新しないと意図せず無限ループに陥りやすい
break
でループを途中終了したり、next
で特定の条件をスキップしたりできる- 実務ではバッチ処理や監視スクリプトなどで無限ループに近い形で使う機会がある
- トラブルが発生するときは、条件式が間違っているケースが多い
Rubyでは、配列の要素を繰り返すならeachメソッド
が優先されることも多いです。
それでも、条件次第で動きを変えたい場面ではwhile文が有力な選択肢になるでしょう。
とくに、終了タイミングを柔軟にコントロールしたいときや、外部からの入力を待ち受けて状態を変えながら動かし続けたいときなどは、Rubyのwhile文がとても役立ちます。
慣れてくると、while文で書くべきところか、それともeachやforなどの他の方法を使ったほうがいいかの判断がスムーズにできるようになるでしょう。
以上を参考にして、ぜひRubyの繰り返し処理をスムーズに活用してみてください。
しっかりとループの仕組みを理解しておけば、複雑な処理をシンプルに記述しやすくなり、プログラムが読みやすく、保守もしやすくなります。