次のluaコードを検討してください。
f = {}
for i = 1, 10 do
f[i] = function()
print(i .. " ")
end
end
for k = 1, 10 do
f[k]()
end
これにより、1から10までの数値が出力されます。この場合、i
外側のループの各反復の値に対して閉じられます。これは私がいつも閉鎖を理解していた方法であり、私はとても幸せでした...
...いくつかのluaコードをc#に移植するまで、同じことをしようとしました:
var f = new Action[10];
for (int i = 0; i < 10; i++)
{
f[i] = (new Action(delegate()
{
Console.Write(i + " ");
}));
}
for (int k = 0; k < 10; k++)
{
f[k]();
}
そして今、私は10という数字を10回印刷します(lua配列は1ベースであることを忘れましょう)。この場合、クロージャは値ではなく変数に対して機能することが実際に発生します。これは、最初のループが終了した後にのみ関数を呼び出すため、非常に理にかなっています。
JavaScriptは同じセマンティクスを持っているようです(変数に近い):
var f = []
for (var i = 0; i < 10; i++)
{
f[i] = function()
{
document.write(i + ' ');
};
}
for (var k = 0; k < 10; k++)
{
f[k]();
}
実際には、両方の動作は非常に理にかなっていますが、もちろん互換性がありません。
これを行う「正しい」方法がある場合は、lua、またはc#とJavaScriptのいずれかが間違っています(他の言語ではまだ試していません)。だから私の質問は、「ループ内で変数を閉じることの「正しい」セマンティクスは何ですか?」です。
編集:私はこれを「修正」する方法を尋ねていません。ループ内にローカル変数を追加し、その変数を閉じて、c#/JavaScriptでluaの動作を取得できることはわかっています。ループ変数を閉じることの理論的に正しい意味は何であるか、そしてどの言語がそれぞれの方法でクロージャを実装するかについての短いリストのボーナスポイントを知りたいです。
編集:私の質問を言い換えると、「ラムダ計算でループ変数を閉じる動作は何ですか?」