5

私の知る限り、主流の言語の中で、他の人の知識と組み合わせる

  • Objective C
  • C#
  • VB.net
  • Java
  • Python
  • ルビー
  • Javascript
  • 舌足らずの発音
  • Perl

クロージャと無名関数があります。プレーンC/C++にはどちらもありません。

これらの言語のクロージャは同じセマンティクスを持っていますか?それらは日常のプログラミングにとってどれほど重要ですか?

背景: AppleのGrand CentralDispatchを対象としたObjectiveCの新しい追加について読んでいて、ブロックのような構造を言語に導入する方法が本当に1つしかないのか、それとも異なる方法があるのか​​を学ぶ必要があると思いました。

4

4 に答える 4

4

主流の言語間のセマンティクスにおける主な意図的な違いは、クロージャによってキャプチャされた変数への変更を許可するかどうかです。Java と Python は「いいえ」と答え、他の言語は「はい」と答えます (まあ、私は Objective C を知りませんが、他の言語は知っています)。変数を変更できる利点は、次のようなコードを記述できることです。

public static Func<int,int> adderGen(int start) {
    return (delegate (int i) {      // <-- start is captured by the closure
                start += i;         // <-- and modified each time it's called
                return start;
            });
}
// later ...
var counter = adderGen(0);
Console.WriteLine(counter(1)); // <-- prints 1
Console.WriteLine(counter(1)); // <-- prints 2
// :
// :

C# (ここで使用されている言語) が舞台裏でまさにそのコードを生成しますが、これは同等のカウンター クラスよりもはるかに少ないコードであることがわかります。欠点は、キャプチャされた変数が実際に共有されることです。そのため、古典的な for ループで多数の加算器を生成すると、驚くことになります...

var adders = new List<Func<int,int>>();

for(int start = 0; start < 5; start++) {
    adders.Add(delegate (int i) {
        start += i;
        return start;
    });
}

Console.WriteLine(adders[0](1)); // <-- prints 6, not 1
Console.WriteLine(adders[4](1)); // <-- prints 7, not 5

startが 5 つのクロージャーすべてで共有されるだけでなくstart++、for ループの最後で繰り返される値が 5 になります。混合パラダイム言語では、Java と Python が正しい考えを持っているというのが私の意見です。キャプチャされた変数を変更したい場合は、代わりにクラスを作成することを余儀なくされたほうがよいでしょう。たとえば、それらをコンストラクターに渡します。私は関数型プログラミングのクロージャーを維持するのが好きです。

ところで、Perl にもクロージャがあります。

于 2009-09-15T03:14:55.473 に答える
3

Javaは、多くの面で言語をシンプルに保ちたいと考えていたため、基本的に(そして今では矛盾しているように聞こえるかもしれませんが)、設計のクロージャを除外しました。

ただし、初日v1.1以降、Javaは同じ機能をサポートしていますが、パラダイム(関数型とOO)を混在させる代わりに、ほぼ同じ目的で機能する匿名の内部クラスの存在を許可しました。それらはクロージャーではなくクラスなので、さらにいくつかの文字を入力する必要があります。

したがって、たとえば、実行するブロックとしてTimerTaskを受け取るTimerを作成するには、次のように記述します。

 Timer timer = new Timer();

 timer.schedule( new TimerTask() {  // this is like the code block. 
     public void run() {
          System.out.println("Hey!");
     }
 },0);

ご覧のとおり、「TimerTask(){...」は匿名内部クラスの定義です。そのインスタンスは、引数として渡された変数にも割り当てることができます。

TimerTask task = new TimerTask() {
     public void run() {
     }
 };


....
timer.schedule( task , 0 ) ;

この種の構成を持つことができますが、それらはクロージャーではありません。

クロージャは、Javaプログラミング言語に追加するためにまだ議論中です。

ジョシュア・ブロックによる興味深い話は次のとおりです。「閉鎖論争」

これは「Java言語を進化させるための原則」に関する記事です。

于 2009-09-14T19:07:22.590 に答える
0

Java にはクロージャや無名関数はありませんが、これらをある程度シミュレートするために使用できる無名クラスはあります。

Java の次のバージョンで言語にクロージャを追加するという競合する提案がありましたが、これらのいずれも公式の変更リストに含まれていません。

于 2009-09-14T18:22:04.057 に答える