からだのブログ

五体満足に生まれてきたことに感謝してブログの名前を「からだ」にしました。

からだのブログ header image 2

Let’s Linq [0]

1月 31st, 2008 · 1 Comment · .net, language

とにかく布教したい気分なので。プログラミング言語という対象に対して、純粋に面白いと感じてるのは久しぶりなので。

例のごとく、C#3.0。その楽しさを喧伝したいだけであって、入門と言えるような整然としたものじゃあないので。念のため。(それでもここ数日の内容よりは「それ向き」)

var vals = new[] { 1, 2, 3 };

C#3.0から暗黙の型宣言を示すvarキーワードが入った。ところで、上記のコードには実は2回「暗黙」が使われている。var と配列の初期化部分。まず最初に、与えてる初期値は int型変数群だから、こいつはint型配列に違いないよね、っていう「暗黙」が働いてる。そして、代入の右辺が決まれば、それを受ける側の型も自ずと決まってくる。つまり、var は int[] になるってわけ。

まあこれは、「ああちょっと便利かもね」っていう機能拡張。今度は、拡張メソッド(「拡張子」とも。俺は「-子」の呼称は嫌い) を使う。書き方などの詳細は調べてもらうとして、要するにこれは既存のクラスにメソッドを後付で追加する機能だ。コレクション類(IEnumerable<T> を実装してるのを便宜上こう呼ぶことにする) のために豊富に拡張メソッドが用意されているので、そいつを使ってみる。

var avg = vals.Average();

をやると、avg には vals の平均、つまり2.0(double で返ってくる)が入るわけ。で、次の例を考えてみる。

var strs = new[] { “a”, “bc”, “def” };
var avg = strs.Average();

どうなるだろうか? 答え、コンパイルエラーになる。そもそも「平均」ってのは数値化されないものには適用できない演算である。だから、当然のごとく文字列の集合に対して「平均」は計算できないし、そうした拡張メソッドのオーバロードも用意されていない。

それでは、「文字列の集合に対する演算『平均』とは、集合の各要素の長さの相加平均である」っていう定義があったらどうだろう。その定義に合うように「文字列」から「長さ」を取り出すメソッドを用意してやれば、ここで定義する平均は計算可能になる。実は、 Average() にはちゃんとそうした需要を満たすオーバロードが用意されてる。言ってしまうと、 Average(Func<string, int> selector) を使えばよい。

ここで、 Func<string, int> が初めて出てきた。これは、stringを引数に取り、intを返すメソッドを示す。そこで、次のようなメソッドを用意してやると、

int getlen(string str)
{
    return str.Length;
}

Average() の引数にこの getlen を渡すことができる。つまり、

var strs = new[] { “a”, “bc”, “def” };
var avg = strs.Average((Func<string, int>) getlen);

とすることで、先の定義に沿う「平均値」が得られるわけだ。ここで、getlen() の関数(何か値を渡して、別の値を取り出す装置)としての機能に着目する。すると、実質的には str.Length の部分しか重要でないことがわかる。実は、C#3.0 では、上記のコードを次のように書くことができる。

var strs = new[] { “a”, “bc”, “def” };
var avg = strs.Average(str => str.Length);

これはラムダ式と呼ばれ、関数型言語からの借用である。ほんとはここからがまた面白いんだけど、まあ後は適当に調べてやってくれw あるプログラミング言語に別の言語のパラダイムが導入されるのって、すごくスリリングだよね。わくわくしちゃう。個人的に、C#1.0 のときよりわくわくしてるわ。

Tags: