redoforやwhile、eachなど、Rubyにはいくつもの繰り返し処理を表現する方法があります。それらはそれぞれ、使用に適したシーンがあり、きちんと使い分けることで、プログラムの可読性(読みやすさ)を上げて不具合を防ぎ、再利用もしやすくできます。これらの繰り返し処理を制御するのに使うのが、break,next,redoです。break,next,redoを使うことで、繰り返しを中断したり、処理を飛ばしたり、やり直したりすることができます。そんな、break,next,redoについて、詳しく解説していきましょう。break,next,redoとは?繰り返しを制御するbreak,next,redoについて解説します。break,next,redoのそれぞれについて紹介しましょう。具体的に以下のプログラムを動かすことで、理解が早まると思います。puts(i+1)endwhileの中にwhileが入っていて、一見ややこしそうなプログラムですが、外のwhileでカウントアップ、内側のwhileではカウントダウンしながら、「()」を表示するプログラムです。この状態では、break,next,redoの処理はすべてコメントアウトされていますので、すべての繰り返し処理を行い、以下のような結果になります。()()()()()()()()()()--10()()()()()()()()()--9()()()()()()()()--8()()()()()()()--7()()()()()()--6()()()()()--5()()()()--4()()()--3()()--2()--1この結果が、break,next,redoの処理を有効にすることによってどう変わるのか、想像しながら読み進めていただければと思います。break繰り返し処理の中には、集計のように決められた回数必ず処理しなければいけない場合と、検索のように結果が出たらそこで止めても良い場合があります。後者の場合に利用するのが、breakです。Rubyは、繰り返し処理の中でbreakに到達すると、ただちに繰り返し処理の次のステップへと処理を移します。その結果、繰り返し処理は終了してしまうわけです。他言語の中には、case〜whenの処理内でbreakが必須なものもあります。Rubyでは不要(むしろ、繰り返し処理の外でbreakがあるとエラーとなる)ですので、気を付けましょう。メリット不要な繰り返し処理を行わないことで、処理の効率が上げり、プログラムのレスポンスが良くなります。breakがなければプログラムしにくいロジックもあります。デメリット繰り返し処理の中で変化していた変数などは、breakの直後の状態になっています。ほとんどの場合は問題ないとは思いますが、もし後処理が必要なもの(例えばファイル操作では、開いたファイルを閉じなければいけません)については、breakすることで後処理がされないことになる可能性がありますので、注意が必要です。動かしてみるbreak01.rbの(1)のコメントを外して動かしてみましょう。中で、カウントダウンされているjが5よりも小さくなると、繰り返し処理を抜けます。jが5よりも小さくなると、「()」が表示されないわけです。動くのか、想像してから動かしてみましょう。(結果)()()()()()--10()()()()--9()()()--8()()--7()--6--5--4--3--2--1next繰り返し処理の中には、どれだけ長い処理があってもかまいません。そのため、プログラムによっては繰り返し処理の中で様々なことを行います。することで、あちこちで繰り返すことを避け、プログラム全体の効率を上げているわけです。特定の条件の場合等には、それ以降の処理を行わずに繰り返しの先頭へ移行して、次の繰り返しへ進みたい場合もあるでしょう。そんなときに利用するのが、nextです。Rubyは、繰り返し処理の中でnextに到達すると、以降の処理をすべて飛ばして、繰り返し処理の先頭へ移行し、次の繰り返し処理を開始します。繰り返し処理を次(next)に進めるわけです。他の言語では、同様の処理を行うのにcontinueというステートメントを利用するものがあります。メリットnextのメリットは、処理を一気に飛ばしてしまえることです。配列に様々なオブジェクトが格納されている場合、特定のオブジェクトの場合だけ処理をするプログラムを作成し、そのオブジェクト以外はnextで処理を飛ばしてしまえば、余計な処理を作成する必要がありません。なにより、余計な処理が行われませんので効率も良いでしょう。デメリットbreakと同様に、後処理を忘れないようにしなければいけません。breakと違って繰り返し処理は行います。何度も後処理忘れを繰り返してしまうことになりますので、メモリ不足など原因特定の難しい不具合の元になる可能性があります。動かしてみるbreak01.rbの(2)のコメントを外して動かしてみましょう。中で、内側のwhileのカウンタであるjが5で割り切れると、以降の処理を無視します。実際に動かして結果を確認してから、プログラムコードを見直してみるのも、良い勉強になります。(結果)()()()()()()()()()--9()()()()()()()()--8()()()()()()()--7()()()()()()--6()()()()--4()()()--3()()--2()--1redo繰り返し処理を続けている中で、すべてをリセットしてやり直すしかない状況になる場合もわずかながらに存在します。(通信のネットワークエラーなどは、最初からやり直すことでスムーズに進むことがあります)そんな場合に、繰り返し処理をやり直すことができるredoが便利です。繰り返し処理の中でredoがあると、Rubyは繰り返し処理を中断して、最初からやり直します。メリット繰り返し処理を作る上で、最初からやり直すシーンはそれほどないかもしれませんが、やり直す処理をredoなしで作ろうとすると、別の繰り返し処理を必要とするなど、複雑なプログラムになることでしょう。それをbreakやnextのようにすっきりと記載できるのは、大きなメリットです。デメリット繰り返し処理を最初からやり直すといっても、後処理が必要なものまでなかったことにはなりませんので、breakやnextと同じ後処理忘れには気を付けなければいけません。それに加えて、やり直す条件が必ず成り立たなくなるようにするか、breakなどで繰り返し処理を中断する処理を組み込んでおかなければ、簡単に無限ループになってしまいますので、安易な使用はたいへん危険です。動かしてみるbreak01.rbの(3)のコメントを外して動かしてみましょう。中で、カウントダウンしているjが7よりも大きい間、繰り返し処理を一旦やめてやり直しています。jが7になるまで、redoの後ろの処理は行われません。どんな図形が表示されるでしょうか?(結果)()()()()()()()()--10()()()()()()()()--9()()()()()()()()--8()()()()()()()--7()()()()()()--6()()()()()--5()()()()--4()()()--3()()--2()--1break,next,redoの違いbreak01.rbで実際の動作を確認しましたが、break,next,redoは、それぞれ繰り返しの制御の仕方が違っています。break,next,redoの違いをまとめると、以下のようになります。・breakは、繰り返し処理を中断する・nextは、以降の処理をスキップして、繰り返し処理を継続する・redoは、繰り返し処理を中断して、最初からやり直すこの違いを理解しておけば、繰り返しの処理を柔軟に効率よく作っていくことができますので、憶えておきましょう。break,next,redoの使いどころbreak,next,redoの動きを理解したところで、どう使うかというのが分からなければ、意味がありません。この3つは繰り返し処理の流れを大きく変え、ときには無限ループまでも引き起こしてしまうような力を持っています。そのため、基本的な使いどころくらいは理解した上で使っていきたいものです。whileやunlessには、なくてはならない相棒?breakやnext,redoは、繰り返し処理の処理を行うかどうかを制御するのに使います。そのため、あらかじめ処理の回数が決まっているforやeachでの使用は、限定的になるかもしれません。(もちろん、プログラムの効率化のために余計な処理を省くことができますので、とても有意義です)つまり、breakやnext,redoの真価が発揮されるのは、whileやunlessなどの「回数が決まっていない」繰り返し処理になるわけです。whileやunlessは、もちろん繰り返しが終わる条件を設定できます。複雑な条件を設定するのは可読性を犠牲にすることになりますので、推奨できません。そのため、最低限の終了条件はwhileやunlessで設定し、その他の条件で繰り返し処理を制御するのにbreakやnextを利用するわけです。実際にユーザーが使用するプログラムで、処理が完了すると終了するようなプログラムは稀です。常に動いており何らかの条件が成立したら(終了ボタンが押されるなど)終了する、というものが一般的でしょう。そのため、多くのプログラムで敢えて「無限ループ」が実装されています。その無限ループの中で、終了ややり直しなどを行うために必要なのが、breakやnext、redoなのです。(※breakやnextがなければ、今のプログラムの形を記載するのは、とても面倒で読みにくいものになることでしょう)つまり、無限ループから抜けたり、無限ループ内での流れを変えたりするための道具として、breakやnextを使うわけです。break,next,redoは、ifと組み合わせて繰り返し処理の中でbreak,next,redoが現れると、それ以降に書かれている処理は無視されます。これらが何の条件もなく現れることはありえないと考えても間違いではないでしょう。そのため、break,next,redoは、ifなどの条件分岐と組み合わせ、一定の条件が成り立った(成り立たなかった)場合のみ実行されるように作るのが一般的です。(※break01.rbでも、breakやnext、redoはifとセットで使用しています)引数を渡すと、繰り返しの戻り値が変わる?ここまでは、break,next,redoを実際にプログラムで使うに当たって必要な、動きや使い方の説明をしてきました。ここからは、もっとRubyらしい理論的な部分を説明しましょう。引数と戻り値ここからの説明のために、「引数」と「戻り値」について最初に解説しておきます。「引数」というのは、処理に渡すデータ(値や文字列など)のことです。「戻り値」というのは、処理結果として返ってくるデータのことです。以下のプログラムでは、putsにiとstr、”test”、lenという引数を渡しています。lenはstrのlengthメソッドからの戻り値(strの文字列の長さ)を受け取っています。len)breakに引数を渡せるそもそも、Rubyではforにも戻り値があります。これは、他の言語からRubyに移行した人にはとても不自然に感じることかもしれませんが、Rubyではごく自然なことです。具体的に見ていきましょう。810..9このように、forの戻り値をretで受け取ることに対して何のエラーも発生せず、最後には内容を表示することもできています。(※forの戻り値は繰り返しの元になるオブジェクトがそのまま返されます)じつは、breakはこの繰り返し処理の戻り値を操作することができるのです。戻り値の操作といってもよく分からないと思いますので、break02-1.rbにbreakを使って途中で繰り返しを抜けるようにしてみましょう。結果の1行目で、50の直前まで出力されていますので、breakが動いて繰り返し処理が完了していることが分かると思います。ポイントは、2行目が空白になっているところです。これは、じつはbreakが返している値です。分かりやすくするために、breakに引数を渡してみます。49break!そうです。breakに渡している引数が、そのまま繰り返し処理の戻り値に上書きされているのです。break02-2.rbでは、breakに引数が渡されていないから、繰り返し処理の戻り値も何も表示されなかったわけです。これは、forだけではなくeachでも使えますので、繰り返し処理を1つの処理ブロックとしてプログラムを作ることができますので、利便性の高い機能といえます。じつはnextにも引数を渡せるbreakと同様に、nextにも引数を渡すことができます。nextの引数も、基本的にはbreakと同じで、戻り値に影響します。breakが繰り返し処理終了時の戻り値であるのに対し、nextの場合は繰り返し処理の1周終了時の戻り値になるところが大きく違います。そのため、break02のようにfor文では意味をなしません。引数付きのnextがその真価を発揮する代表的な繰り返し処理は、繰り返しごとの処理結果を配列として戻り値を返すmapメソッドです。以下のように3で割り切れる場合は処理を飛ばしてしまう場合を考えましょう。100]結果のように、3で割り切れる要素は処理をしていませんので、無効値(nil)が格納されてしまっています。いった場合に、引数付きnextが役立ちます。処理をしませんので、引数付きnextを使って、0を格納するようにしましょう。100]先ほどnilだった場所に0が格納されました。これで、処理がぐっと楽になると思います。他言語のcontinueと違って、繰り返し処理を中断しているわけではない以上のように、Rubyのbreakやnextは、「戻り値を設定する」という機能を持っています。これはつまり、多くのサイトや書籍で他言語のbreakやcontinueと同じようなものと説明されていますが、じつは内部的にまったく違っているということを理解しておきましょう。他言語のbreakやcontinueは、本当に処理の流れを書き換えている場合がほとんどです。(「次はどの命令を実行するか」を示している値を直接書き換えています)しかし、Rubyのbreakやnextは、「戻り値を返している=処理を完了の機能を実行している」ということになります。この理解があれば、breakやnextに引数があることに違和感を覚えることはなくなるでしょう。プログラムを作る上で、その動きはほぼ同じですので、多くのサイトや書籍が噓を伝えているわけではありません。breakpointで検索してきた人へ最後に、本稿を訪れる人の中の「breakpoint」で検索してきた人へ向けての補足を書いておきます。本稿で説明しているbreakは、あくまでも繰り返し処理を終了するbreakメソッドについてです。「breakpoint」とは、まったく違うものです。「breakpoint」というのは、ほぼすべてのデバッガにある機能で、デバッグ時にプログラムを一時停止するポイントのことを意味します。この「breakpoint」が設定された状態で、デバッガ上でプログラムを動かすと、プログラムがbreakpointに達した瞬間にプログラムは停止し、そのときの変数の状態などを確認、変更することができるようになります。この機能はプログラムの動きを解析する上でとても便利な機能ですので、ぜひ積極的に使うことをおすすめします。「【Ruby入門説明書】stepについて解説」で紹介しているRuby標準のデバッガにも搭載されており、紹介していますので、ご参照いただけますと幸いです。まとめ長くなってしまいましたが、break,next,redoの解説は以上です。break,next,redoは、機能的にあまり目立つことはなく、簡単に説明されていることが多いですが、うまく使えばプログラムの効率を上げ、プログラムコードをすっきりと見やすくしてくれる効果があります。その反面、使い方を誤ると意図しない無限ループに陥ることもある両刃の剣といえるものです。深く追求すればもっと詳しく書けますが、文章では長くなりますので、これ以上のことを知りたければ、プログラム教室などで直接講師に聞いてみることをおすすめします。いった目立たないTIPSは、プログラムをかじったことのある人は大好物ですので、いろいろと教えてくれることでしょう。WEBCAMPを運営しています。人生が変わるほど「グッとくる」成長体験を、プログラミング学習を通してお届けしています。【元自衛官】の人生を変えた半年!エンジニアへの道のり。WEBCAMPで安心してエンジニア転職を目指そう「スキルがないし...」「失敗したくないし...」カウンセラーがあなたのキャリアを真剣に考え、ご相談に乗ります。