好的,首先让我们分解一下你的 JavaScript 做了什么。
function()
{
var id = 0;
return function() { return id++; };
}
这段代码创建了一个没有名称、不带参数的函数。当调用该函数时,会返回一个新的函数。内部函数将可以访问局部作用域变量,并且该变量将成为内部函数的状态的一部分。
每次调用该函数,它都会返回一个新函数。该新函数将具有自己的状态(毕竟 var id = 0;
要发挥作用)。每次外部函数的调用都将返回一个具有新状态的新函数。
代码示例:
(function()
{
var id = 0;
return function() { return id++; };
})
用一对括号将函数包起来。这是为了运算符优先级规则而需要的,以便使以下内容正常工作:
(function()
{
var id = 0;
return function() { return id++; };
})()
这段代码创建了一个函数,并在最后通过()
调用了这个函数。这样做的目的就是调用外部函数,让它创建一个拥有自己作用域的内部函数并返回。
在这个表达式中,外部函数已经消失了。它已经不存在了,你无法再访问它。你只是为了调用它而创建了它,然后让它被垃圾回收器丢到了垃圾桶里。
综上所述,我们可以看出以下语句的含义:
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
创建外层函数,调用返回新函数的函数,然后将内部函数存储在名为uniqueID1
的变量中。
如果您需要证明这是真实的,请在您的HTML中尝试执行此操作:
var uniqueMaker = function()
{
var id = 0;
return function() { return id++; };
};
var uniqueID1 = uniqueMaker();
var uniqueID2 = uniqueMaker();
你会得到与你复制粘贴版本相同的答案。
如果我们想让C++代码模拟这个过程,我们需要使用正确的C++代码执行每个步骤。
首先是内部函数。在C++中,不存在词法作用域。因此,您不能返回引用其他作用域变量的函数。您只能返回一个带有另一个作用域变量的
副本的lambda函数。此外,除非您明确允许,否则lambda函数不能修改作用域。因此,内部代码应该像这样:
int id = 0;
return [=]() mutable { return ++id; };
这很好,但现在我们需要创建一个lambda函数来返回这个具有状态的lambda函数。在C++中,具有状态的函数与函数指针不同。由于lambda的类型是由编译器定义的,因此无法为其命名。因此,我们必须使用std::function
作为外部函数的返回类型。
[]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
}
这将创建一个Lambda函数,当调用它时,它将返回一个具有自己状态的内部函数。该状态与对此函数的任何后续调用无关。就像JavaScript示例一样。
现在,仅此还不够。请记住,您的JavaScript创建了外部函数,调用它并仅存储其返回值。外部函数本身被丢弃。所以我们需要模仿这个过程。幸运的是,在C++中可以很容易地实现这一点;它看起来就像JavaScript:
([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})()
最后,我们将其存储在变量中:
auto uniqueID1 = ([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})();
uniqueID1
的类型将是 std::function<int()>
,而不是外部函数的类型。外部函数只是一个用于创建内部作用域的临时对象。