考虑以下 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 行为。我想知道关闭循环变量的理论上正确含义是什么,以及哪些语言以每种方式实现关闭的简短列表的奖励积分。
编辑:改写我的问题:“在 lambda 演算中关闭循环变量的行为是什么?”