Rubyのcatchとthrowを徹底解説!複雑な多重ループから一気に脱出する方法
生徒
「Rubyで繰り返し処理を勉強していますが、二重や三重のループの中から一気に外側へ抜け出したいときはどうすればいいんですか?」
先生
「良いところに気が付きましたね。Rubyには『catch』と『throw』という仕組みがあって、それを使えばどんなに深い場所からでも一瞬で指定した場所まで戻ることができるんですよ。」
生徒
「一瞬で戻れるんですか?なんだか魔法みたいですね!でも、難しそうな名前です……。」
先生
「使い方はとってもシンプルです!『ボールを投げて(throw)、受け止める(catch)』というイメージで考えると分かりやすいですよ。さっそく仕組みを見ていきましょう。」
1. catchとthrowとは?非局所ジャンプの基本
Rubyのプログラムを書いていると、繰り返しの処理(ループ)を何重にも重ねることがあります。通常、ループを抜けるときには「break(ブレイク)」という命令を使いますが、breakは「今いる一番内側のループ」を一つ抜けることしかできません。
しかし、特定のエラーが見つかったり、目的のデータが見つかったりしたときに、二重、三重のループをすべて飛び越えて、一気に親となる場所まで戻りたいことがあります。この「離れた場所へ一気にジャンプする機能」のことを専門用語で非局所ジャンプ(ひきょくしょじゃんぷ)と呼びます。
パソコンの操作に例えるなら、フォルダを何個も開いて深い階層にいるときに、一つずつ戻るボタンを押すのではなく、一気にデスクトップ画面まで戻るような感覚です。これを実現するのが、Rubyのcatch(キャッチ)とthrow(スロー)の組み合わせなのです。
Rubyの文法を基礎からしっかり固めたい人や、 現場で役立つ「テスト駆動開発」の考え方まで身につけたい人には、 評価の高いこの一冊がおすすめです。
プロを目指す人のためのRuby入門をAmazonで見る※ Amazon広告リンク
2. ボールを投げて受け止める!動作のイメージ
この仕組みを理解するためには、スポーツのキャッチボールを想像してみてください。
まず、目的地となる場所に「ここで受け止めるよ!」という名前付きのグローブを構えます。これがcatchです。そして、深いループの中などから「ボールを投げるよ!」と合図を送るのがthrowです。
ボールが投げられると、Rubyはその瞬間に今やっている作業をすべて中断し、同じ名前のグローブを持っているcatchの場所までひとっ飛びで戻ります。名前が一致している必要があるため、迷子になる心配もありません。このシンプルさが、複雑なプログラムを読みやすく整えてくれる大きな武器になります。
3. 実際に書いてみよう!二重ループからの脱出例
それでは、実際にRubyのコードでどのように書くのか見てみましょう。以下の例では、二重になった繰り返し処理の中から、特定の条件で見つかった瞬間に外側へ飛び出します。
# :exit_loop という名前のグローブを構える
catch :exit_loop do
[1, 2, 3].each do |i|
[10, 20, 30].each do |j|
puts "i: #{i}, j: #{j} を確認中..."
# iが2で、jが20のときに、一気に外へ出たい!
if i == 2 && j == 20
puts "目的の数値が見つかりました!一気に脱出します。"
throw :exit_loop
end
end
end
puts "ここは実行されません。"
end
puts "キャッチされた後の場所です。無事に脱出しました!"
実行結果は以下のようになります。
i: 1, j: 10 を確認中...
i: 1, j: 20 を確認中...
i: 1, j: 30 を確認中...
i: 2, j: 10 を確認中...
i: 2, j: 20 を確認中...
目的の数値が見つかりました!一気に脱出します。
キャッチされた後の場所です。無事に脱出しました!
このように、throwが呼ばれた瞬間にすべてのループを突き抜けて、catchの終わりの部分までジャンプしていることがわかります。
4. シンボルについて学ぼう!名前の付け方のルール
コードの中で使われている「:exit_loop」のように、頭にコロン(:)がついた言葉をRubyではシンボルと呼びます。
初心者の方には少し聞き馴染みがないかもしれませんが、これは「名前そのもの」を表す特別なデータです。普通の文字列("exit_loop")と似ていますが、シンボルのほうがパソコンにとって処理が軽く、名前として使うのに適しています。
catchとthrowを使うときは、必ず同じシンボルを名前に指定してください。名前が違うと、誰が投げて誰が受け取るのかがわからなくなり、エラーが発生してしまいます。名前は自分で決めることができるので、何のためのジャンプなのかがわかるような名前をつけるのがコツです。
5. throwで値を渡す!ジャンプと一緒にデータを届ける
実は、throwはただジャンプするだけでなく、ジャンプ先に「お土産」としてデータを渡すこともできます。
目的地であるcatchは、受け取ったデータを自分の処理の結果として受け取ることができます。これを使うと、「何が原因で脱出したのか」という情報をジャンプ先ですぐに使うことができるようになります。
# お土産を受け取るための変数 result
result = catch :find_item do
["リンゴ", "バナナ", "オレンジ"].each do |fruit|
if fruit == "バナナ"
# 第二引数に「見つかったよ」というお土産を添える
throw :find_item, "熟したバナナが見つかった!"
end
end
"何も見つかりませんでした" # 何も投げられなかった場合
end
puts "結果: #{result}"
このプログラムでは、バナナを見つけた瞬間にメッセージを持ってジャンプします。その結果、変数resultにメッセージが代入されます。非常に効率的ですね。
6. 例外処理(raise/rescue)との使い分け
プログラミングには、似たような仕組みで「raise」や「rescue」というエラー対応のための機能があります。これらもジャンプする機能を持っていますが、用途がはっきりと異なります。
例外処理(raise/rescue)は、「予期せぬエラー」が起きたときに使う緊急事態のためのものです。例えば、パソコンが故障した、ファイルが突然消えた、といったトラブルに対応します。
対して、catch/throwは、エラーではなく「プログラムの正常な流れの一部」として使います。多重ループから抜けるのはエラーではありませんよね。あくまで「作業が完了したから戻る」という自分自身の意図した制御のために使うのが正しいルールです。この使い分けができるようになると、中級者の仲間入りです!
7. 複雑な条件分岐を一掃する魔法
もしcatch/throwを使わなかったら、どうなるでしょうか。深いループの中から外に出るために、「脱出フラグ」というものを用意しなければなりません。
「見つかったら、まず内側のループを抜けて、次に変数を確認して、外側のループも抜けて……」と、何度もif文を書いて階段を降りるように慎重に抜ける必要があります。これでは、コードがどんどん複雑になり、読み間違いや書き間違いが増えてしまいます。
catch/throwを使えば、こうした余計なフラグ管理を一掃できます。プログラムがスッキリと読みやすくなり、後から見返したときにも「ああ、ここで一気に戻るんだな」と一目で理解できるようになります。
8. 実践編:商品の在庫チェックシステム
最後に、もう少し具体的な例を考えてみましょう。たくさんのお店の中から、特定の商品の在庫があるお店を探し出すプログラムです。在庫が見つかったら、もう他のお店を探す必要はありません。
stores = {
"東京店" => ["ペン", "ノート"],
"大阪店" => ["ハサミ", "消しゴム", "ホッチキス"],
"名古屋店" => ["定規", "コンパス"]
}
search_target = "消しゴム"
found_store = catch :found do
stores.each do |store_name, items|
items.each do |item|
puts "#{store_name} で #{item} を確認しています..."
if item == search_target
throw :found, store_name # 見つかった店名を投げる
end
end
end
"どこのお店にもありません"
end
puts "【調査結果】: #{search_target} は 「#{found_store}」 にありました!"
このコードでは、大阪店で消しゴムを見つけた瞬間に名古屋店の調査をスキップして、すぐに結果を表示しています。無駄な処理を省く素晴らしい書き方です。
9. 学習のポイントと注意すべきこと
catch/throwはとても便利ですが、乱用しすぎると「プログラムのあちこちでワープが発生する」状態になり、かえって流れが追いにくくなることもあります。
まずは「基本はbreakで対応できないか?」を考え、どうしても二重以上の深い場所から脱出したいときに、この最強の道具を引っ張り出すのが良いでしょう。
また、初心者のうちは「コロン(:)を忘れない」「シンボル名を一致させる」という二点を特に意識してください。これさえ守れば、多重ループの迷路も怖くありません。一つずつ、自分の思い通りにプログラムを操る楽しさを味わっていきましょう。
10. コンピュータと対話する楽しさ
今回学んだcatchとthrowは、Rubyというプログラミング言語が持つ「表現力」の豊かさを象徴する機能の一つです。
「これを探して、見つかったらここまで戻ってきてね」とコンピュータに伝える。そして、コンピュータがその通りに動いてくれる。プログラミングの醍醐味は、まさにこの対話にあります。
パソコンを触るのが苦手だった方も、こうした道具を一つずつ覚えていけば、自分だけの便利なツールを作れるようになります。例外処理や条件分岐、そして今回の非局所ジャンプ。これらを組み合わせて、世界に一つだけのプログラムを完成させてみてくださいね。