【Unity・C#】どのような手順でラムダ式になったのか知る

前回、デリゲードについての記事を書きました。 nasan-log.hatenablog.com

今回はこのデリゲートをさらに使いやすくする機能、
ラムダ式についてです。

最小のラムダ式

ラムダ式(Lambda expressions)とは、
その場使い捨ての関数を作ることが出来る機能です。
learn.microsoft.com

何もしないラムダ式の構文はこちら。

Action func = () => {};
func.Invoke(); // 実行

何やら見慣れない構文をしています。
私は最初見たとき意味が分かりませんでした。

どのような手順があってこうなったのか書きながら考えていきます。

関数からデリゲードへ

まずは関数をデリゲードにする処理から。

端的に説明すると、あらかじめ作った Func<int, int, int>型に、
AddFunction()関数を入れ、Invoke()で実行させています。

前回の記事で詳しく解説しています。 nasan-log.hatenablog.com

/// <summary> 初期化処理 </summary>
private void Start()
{
    int value = AddFunction(1,1);

    // value == 2;
    Debug.Log(value.ToString());
}

/// <summary> 足し算をする関数 </summary>
private int AddFunction(int num1, int num2)
{
    return num1 + num2;
}

/// <summary> 初期化処理 </summary>
private void Start()
{
    Func<int, int, int> addFunc = AddFunction;
    int value = addFunc.Invoke(1, 1);

    // value == 2;
    Debug.Log(value.ToString());
}

/// <summary> 足し算をする関数 </summary>
private int AddFunction(int num1, int num2)
{
    return num1 + num2;
}

デリゲードから丁寧なラムダ式

さて、デリゲードを実行させるために
いちいち関数を用意していてはデリゲードの意味がありません。
これをその場で、使い捨ての関数を作るのがラムダ式です。

ラムダ式の基本的な構文は
( 引数 ) => { 処理 }; です。

先ほどのAddFunction()をラムダ式で丁寧に書くと以下のような形になります。

/// <summary> 初期化処理 </summary>
private void Start()
{
    Func<int, int, int> addFunc = (int num1, int num2) =>
    {
        return num1 + num2;
    };
    int value = addFunc.Invoke(1, 1);

    // value == 2;
    Debug.Log(value.ToString());
}

AddFunction()の行がまるまる消えてすっきりしましたね!
関数名を定義せず()の中に引数{}の中に処理を書くことが、
ラムダ式の基本となります。

丁寧なラムダ式からラムダ式

実は上記のラムダ式の書き方はあまり意味がなかったりします。
ラムダ式簡素に使える
つまりタイピング量をできるだけ減らして関数を作ることを目的としています。

では無駄な部分を省いていきます。
まずは処理のための{}の部分の改行は必要ありません。
これで3行減り、視覚的に見やすくなりました。

/// <summary> 初期化処理 </summary>
private void Start()
{
    Func<int, int, int> addFunc = (int num1, int num2) => { return num1 + num2; };
    int value = addFunc.Invoke(1, 1);

    // value == 2;
    Debug.Log(value.ToString());
}

次に引数である(int num1, int num2)の部分を省いていきます。
既に行内でFunc<int, int, int>と記述されており、
第1,第2引数にintが使われるということが推測できるため必要ありません。

/// <summary> 初期化処理 </summary>
private void Start()
{
    Func<int, int, int> addFunc = (num1, num2) => { return num1 + num2; };
    int value = addFunc.Invoke(1, 1);

    // value == 2;
    Debug.Log(value.ToString());
}

最後に{ return num1 + num2; };の部分を省いていきます。 処理自体が一行で済むこと、
行内でFunc<int, int, int>と記述されており、
戻り値にintが戻るということが推測できるため必要ありません。

/// <summary> 初期化処理 </summary>
private void Start()
{
    Func<int, int, int> addFunc = (num1,  num2) =>  num1 + num2;
    int value = addFunc.Invoke(1, 1);

    // value == 2;
    Debug.Log(value.ToString());
}

かなり短くなりました!

おわりに

どのような感じでこのような構文になったのか順を追っていくことで
理解が深まったと思います。

より詳しい解説については、とりすーぷさんが書いた
Qiitaの記事が非常に分かりやすいのでぜひ見てください! qiita.com

参考にしたもの

ラムダ式 - ラムダ式と匿名関数 | Microsoft Learn
【C#】わかった"つもり"になれる「ラムダ式」解説 - Qiita