Kikuchy's Second Memory

技術のこととか、技術以外のこととか、思ったことを書き留めています。

How to ラムダ式

先日、11月11日に Windows 8発売記念! Microsoft Student Partners 主催 Windows ストア アプリ 開発の会 in 東京 #2 : ATND というイベントを、MSPの三村さんと開催させていただきました。
会自体はとても和やかで、参加してくださった皆様に満足していただけたようで何よりでした!


さて。この帰り道に、今回初めてC#に触れたという@kouhei_szk君と話をしていて、@numa08さんを含めて、ラムダ式の話で盛り上がりまして。



ところで、ラムダ式ってご存知ですか?



このブログでも、サンプルコードの中にたまに入っていたりするのですが、ここで私の勉強もかねて、詳しく解説したいと思います。



C#におけるラムダ式とは、乱暴に一言で言ってしまうと、名前のない関数(匿名関数)のことです。

さて、名前のない関数を書けると何が良いのでしょうか?
実はこんな利点があります。


1. イベントハンドラが簡単に書ける
ラムダ式(と、delegateを使った無名関数の宣言)ができるまで、何かしらのイベントハンドラ(イベントが起きた時に呼び出されるメソッド)を書くときには、イベントハンドラ用のメソッドを宣言しなければいけませんでした。
例えばこんな感じ。

// イベントハンドラ用メソッドの宣言
private OnHogeHoge(object sender, EventArgs e)
{
    fugagufa();
}

……

// どこか別の場所で
// あるオブジェクトがクリックされたときに、OnHogeHoge()が呼ばれる
someObject.Click += OnHogeHoge;

XAMLとかでUIが分離されているときのクリックのイベントだったら、保守性のためにイベントハンドラには名前をつけて管理するべきだと思いますが…
「どう考えても一度しか使わないし、しかもハンドラの内容も短い」なんてときには、わざわざメソッドを宣言したくないこともあるのですよ。
ラムダ式を使えばこれが簡単に、

someObject.Click += (sender, e) => { fugafuga(); };

と書けてしまいます。
すっきりしましたね!


2. LINQがすっきり書ける
みんな大好きですよね、LINQ。リストの中から条件に合う要素だけ取り出したり、データベースの問い合わせもできちゃったりが一つの文法で、しかもすっきり書けちゃう。
このLINQ、最近はクエリ式で書くのが流行りのようですが、RoRで見るようなメソッドチェーンでも使うことができます。
そしてメソッドチェーンする場合は、ラムダ式を使うとすっきり書くことができます。

private bool initialA(string str)
{
    return str[0] == 'A';
}

……

var initialAs = nameList.Where(initialA);

これがラムダ式を使えば、

var var initialAs = nameList.Where((str) => str[0] == 'A');

なんてシンプル!


他にもラムダ式の使い道はたくさんあります。
JavaScript

var someMethod = function(arg){ …… };

と書くのと同じようなことをしている訳ですしね。



さて、ではラムダ式をどうやって書くのか。
基本的に「=>」がラムダ式を表す演算子だと思ってください。

// 引数がないときは、 => の前に () が必要
// => の後は文か式を書く。文はreturnで示した値が、式はその評価値が返る。
// 引数なし、返り値整数型。右辺は文。
Func<int> f1 = () => { return 1; };

// 引数が一つだけのときのみ、 () は省略可能
// 引数1個、返り値文字列型。右辺は式。
Func<int, string> f2 = x => string.Format("{0}", x);

// 引数の型は勝手に推論してくれる。もちろん、明記もできる
// 引数2個、返り値倍精度浮動小数点数。右辺は式。
Func<int, int, double> f3 = (x, int y) => Math.Sqrt(x * x + y * y);

// 匿名関数で処理をする
double fuga = f3(f1(), 3);

// async を付けることも可能
// 右辺は文。
Func<Task<string>> f4 = async () => { return await GetSomtingAsync(); };
string hoge = await f4();

// クロージャもできる
Func<Func<int>> cl = () =>
{
    int i = 0;
    return () => { return i++; };
};
Func<int> inc = cl();
inc(); // 0
inc(); // 1
inc(); // 2

私が知っている書き方だとこんな感じ。
見るだけだと有難味が少ないですが、書いてみると楽しくなっちゃうのがラムダ式なのです。

おいでよ! ラムダ式の森!



参考