Ama*_*ron 17 closures functional-programming
我已经阅读了有关stackflow和其他来源的闭包的前几个主题,有一件事仍然令我感到困惑.从技术上来说,闭包只是包含函数代码和该函数中绑定变量值的数据集.
换句话说,从技术上讲,以下C函数应该是我理解的闭包:
int count()
{
static int x = 0;
return x++;
}
Run Code Online (Sandbox Code Playgroud)
然而,我读到的所有东西似乎暗示闭包必须以某种方式将函数作为第一类对象传递.此外,通常似乎暗示闭包不是程序编程的一部分.这是一个解决方案与它解决的问题过度相关的情况,还是我误解了确切的定义?
Pet*_*ddy 22
不,那不是关闭.您的示例只是一个函数,它返回递增静态变量的结果.
这是封闭如何工作:
function makeCounter( int x )
{
return int counter() {
return x++;
}
}
c = makeCounter( 3 );
printf( "%d" c() ); => 4
printf( "%d" c() ); => 5
d = makeCounter( 0 );
printf( "%d" d() ); => 1
printf( "%d" c() ); => 6
Run Code Online (Sandbox Code Playgroud)
换句话说,makeCounter()的不同调用产生不同的函数,它们自己在词汇环境中绑定变量,它们已经"封闭"了.
编辑:我认为像这样的例子使得闭包比定义更容易理解,但是如果你想要一个定义我会说,"闭包是一个函数和一个环境的组合.环境包含函数中定义的变量以及函数创建时可见的函数.只要函数存在,这些函数必须保持可用."
Meh*_*ari 12
对于确切的定义,我建议查看其维基百科条目.这特别好.我只想用一个例子来澄清它.
假设这个C#代码片段(它应该AND
在列表中执行搜索):
List<string> list = new List<string> { "hello world", "goodbye world" };
IEnumerable<string> filteredList = list;
var keywords = new [] { "hello", "world" };
foreach (var keyword in keywords)
filteredList = filteredList.Where(item => item.Contains(keyword));
foreach (var s in filteredList) // closure is called here
Console.WriteLine(s);
Run Code Online (Sandbox Code Playgroud)
做C#这是一个常见的陷阱.如果你看一下里面的lambda表达式Where
,你会发现它定义了一个函数,它的行为取决于它定义站点上变量的值.这就像将变量本身传递给函数,而不是传递给该变量的值.实际上,当调用此闭包时,它会在那时检索keyword
变量的值.这个样本的结果非常有趣.它打印出两个 "世界你好"和"再见世界",这是不是我们想要的.发生了什么?正如我上面所说,我们用lambda表达式声明的函数是对keyword
变量的闭包,所以这就是:
filteredList = filteredList.Where(item => item.Contains(keyword))
.Where(item => item.Contains(keyword));
Run Code Online (Sandbox Code Playgroud)
并且在关闭执行时,keyword
具有值"world",因此我们基本上使用相同的关键字过滤列表几次.解决方案是:
foreach (var keyword in keywords) {
var temporaryVariable = keyword;
filteredList = filteredList.Where(item => item.Contains(temporaryVariable));
}
Run Code Online (Sandbox Code Playgroud)
由于temporaryVariable
作用域是循环体,因此foreach
在每次迭代中,它都是一个不同的变量.实际上,每个闭包都将绑定到一个不同的变量(这些变量temporaryVariable
在每次迭代时都是不同的实例).这一次,它会给出正确的结果("hello world"):
filteredList = filteredList.Where(item => item.Contains(temporaryVariable_1))
.Where(item => item.Contains(temporaryVariable_2));
Run Code Online (Sandbox Code Playgroud)
其中temporaryVariable_1
的值为"hello",temporaryVariable_2
并且在关闭执行时具有值"world".
请注意,闭包已经导致变量的生命周期延长(它们的生命应该在循环的每次迭代之后结束).这也是封闭的重要副作用.
根据我的理解,闭包还必须能够访问调用上下文中的变量.闭包通常与函数式编程相关联.语言可以包含来自不同类型的编程视角,功能,程序,命令,声明等的元素.它们的名称来自于在指定的上下文中被关闭.它们也可能具有词法绑定,因为它们可以使用在该上下文中使用的相同名称来引用指定的上下文.您的示例没有引用任何其他上下文,而是全局静态上下文.
来自维基百科
闭包关闭自由变量(不是局部变量的变量)