ブロック(その1)
プログラマとして長くコードを書いていると、重複するロジックや、詳細を隠蔽したいロジックをサブルーチンにブレークダウンする必要性を本能的に感じるはずだが、それと相反して、できるだけ現在のコンテキストの中で処理を書きたい欲求に駆られることが多い。(式の評価結果や変数をパラメタとして遠くのルーチンやモジュールに引き回すのが無駄に思うのだ。)
JavaやC#を使う場合、この相反する目的を少しスマートに解決することができる。例えばC#のArrayクラスはPredicate匿名デリゲートを使って
string mens = { "ラーメン", "つけ麺", "僕イケメン", "冷麺"}; string trueMen = Array.FindAll(mens, delegate(string men) { return (men.EndsWith("麺")); }); foreach (string men in trueMen) { Console.WriteLine(men); }
と、合致条件を記述するコードを他のブロックに分離しつつ現在のコードのコンテキスト内で動作させることができる。(インタフェースと無名インナークラスを使えばJavaでも同様に実現できる)
Rubyのブロックはそれ自体が型やオブジェクではなく、コードのコンテキスト中で他のコードの実行を付加するために用意された標準のメカニズムである。(型やオブジェクトではないってのがミソ)
上記のC#のコードと同じ処理をRubyで書くと以下のようになる。
mens = ["ラーメン", "つけ麺", "僕イケメン", "冷麺"] trueMen = mens.find_all { |men| men =~ /麺$/ } trueMen.each { |men| p men }
メソッドの書き方自体は似ているが、Rubyの場合、C#のようにデリゲートをメソッドのパラメタとしている訳ではないことに注意が必要だ(Arrayクラスのfind_allやeachメソッドに引数は無い)