1. ホーム
  2. c#

[解決済み】ローカル関数とラムダ C# 7.0

2022-04-12 15:36:48

質問

の新しい実装を見ています。 C# 7.0 で、ローカル関数を実装しているのは面白いけど、ラムダ式よりローカル関数を優先するシナリオが想像できないし、両者の違いは何なのか。

確かにラムダは anonymous しかし、ローカル関数がラムダ式より優れているという現実的なシナリオが思いつかないのです。

何か例があれば教えてください。ありがとうございます。

どのように解決するのですか?

これは、ローカル関数が最初に議論された C# Design Meeting Notes で Mads Torgersen が説明したものである。 :

ヘルパー関数が欲しいのですね。この関数は一つの関数の中だけで使用され、その関数のスコープ内にある変数や型パラメータを使用する可能性があります。一方、ラムダと違って、第一級のオブジェクトとして使う必要はないので、デリゲート型を与えて実際のデリゲート・オブジェクトを割り当てる必要はない。また、再帰的、汎用的、あるいはイテレータとして実装したい場合もあります。

もう少し拡大解釈すると、メリットは

  1. 性能を発揮します。

    ラムダを作成する際、デリゲートを作成する必要がありますが、この場合、不要なアロケーションとなります。ローカル関数は本当にただの関数で、デリゲートは必要ありません。

    ラムダは通常、変数をクラスに取り込みますが、ローカル関数は、構造体(この例では、"S "を使用して渡されます)を使用して、ローカル変数をより効率的に取り込むことができます。 ref を使用することで、アロケーションを回避することができます。

    また、ローカル関数の呼び出しも安価になり、インライン化も可能で、さらにパフォーマンスが向上する可能性があります。

  2. ローカル関数は再帰的であることが可能です。

    ラムダも再帰的であることが可能ですが、その場合、最初に null をデリゲート変数に、次にラムダを指定します。ローカル関数は当然ながら再帰的である(相互に再帰的であることを含む)。

  3. ローカル関数はジェネリックにすることができます。

    ラムダは具象型を持つ変数に代入しなければならないので、ジェネリックにはできません(その型は外部スコープからジェネリック変数を使用できますが、同じことではありません)。

  4. ローカル関数は、イテレータとして実装することができます。

    ラムダは yield return (そして yield break を実装するためのキーワードです。 IEnumerable<T> -を返す関数です。ローカル関数は可能です。

  5. ローカル機能の方が見栄えがする。

    これは上記の引用文には書かれていませんし、私の個人的な偏見かもしれませんが、ラムダをデリゲート変数に代入するよりも、通常の関数構文の方が見栄えが良いように思います。また、ローカル関数の方がより簡潔です。

    比べてみてください。

    int add(int x, int y) => x + y;
    Func<int, int, int> add = (x, y) => x + y;