我看过关闭的样本 - 什么是'关闭'?
任何人都可以提供何时使用闭包的简单示例?
具体来说,闭包有意义吗?
让我们假设语言没有关闭支持,如何才能实现类似的东西呢?
不要冒犯任何人,请用c#,python,javascript,ruby等语言发布代码示例.
很抱歉,我还不懂函数式语言.
闭包只是很棒的工具.什么时候使用它们?任何时候你喜欢...正如已经说过的,另一种选择是写一个班级; 例如,在C#2.0之前,创建参数化线程是一个真正的斗争.使用C#2.0,您甚至不需要`ParameterizedThreadStart':
string name = // blah int value = // blah new Thread((ThreadStart)delegate { DoWork(name, value);}); // or inline if short
将其与创建具有名称和值的类进行比较
或者同样搜索列表(这次使用lambda):
Person person = list.Find(x=>x.Age > minAge && x.Region == region);
再次 - 替代方法是编写一个具有两个属性和方法的类:
internal sealed class PersonFinder { public PersonFinder(int minAge, string region) { this.minAge = minAge; this.region = region; } private readonly int minAge; private readonly string region; public bool IsMatch(Person person) { return person.Age > minAge && person.Region == region; } } ... Person person = list.Find(new PersonFinder(minAge,region).IsMatch);
这与编译器在引擎盖下的工作方式相当(实际上,它使用公共读/写字段,而不是私有只读).
C#捕获的最大警告是观察范围; 例如:
for(int i = 0 ; i < 10 ; i++) { ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(i); }); }
这可能无法打印您所期望的内容,因为变量 i用于每个.你可以看到重复的任何组合 - 甚至10 10.您需要仔细确定C#中捕获的变量的范围:
for(int i = 0 ; i < 10 ; i++) { int j = i; ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(j); }); }
这里每个j都被单独捕获(即不同的编译器生成的类实例).
乔恩斯基特具有良好的博客条目涵盖C#和Java封在这里 ; 或者更多细节,请参阅他的深度C#一书,其中有完整的章节.
我同意以前的"所有时间"的回答.当您使用函数式语言或lambdas和闭包很常见的语言进行编程时,您甚至不会注意到它们.这就像问"功能的场景是什么?" 或"循环的场景是什么?" 这不是为了使原始问题听起来愚蠢,而是指出在语言中有一些构造,你没有根据特定场景定义.你只是一直使用它们,对于一切,它是第二天性.
这在某种程度上让人想起:
尊敬的大师Qc Na和他的学生Anton一起走路.希望提醒大师进行讨论,安东说:"师父,我听说物体是件好事 - 这是真的吗?" Qc Na怜悯他的学生并回答说:"愚蠢的学生 - 物品只是一个穷人的封闭物."
被责备,安东从他的主人那里离开并回到他的牢房,打算研究关闭.他仔细阅读了整个"Lambda:The Ultimate ..."系列论文及其表兄弟,并实现了一个带有基于闭包的对象系统的小型Scheme解释器.他学到了很多,并期待通知他的主人他的进步.
在他与Qc Na的下一次行走中,安东试图通过说"师父,我努力研究这件事,并且现在明白对象真的是一个穷人的封闭"来打动他的主人.Qc Na用他的棍子打了安东,说:"你什么时候学习?关闭是一个穷人的对象." 那一刻,安东开悟了.
(http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html)
使用闭包的最简单的例子是称为currying.基本上,假设我们有一个功能f()
,当有两个参数调用a
,并b
补充说他们在一起.所以,在Python中,我们有:
def f(a, b): return a + b
但是,让我们说,为了争论,我们只想一次调用f()
一个参数.所以,而不是f(2, 3)
,我们想要f(2)(3)
.这可以这样做:
def f(a): def g(b): # Function-within-a-function return a + b # The value of a is present in the scope of g() return g # f() returns a one-argument function g()
现在,当我们打电话f(2)
,我们得到了一个新的功能,g()
; 这个新函数带有来自范围的变量,因此f()
据说它关闭了这些变量,因此称为闭包.当我们调用时g(3)
,变量a
(由定义约束f
)被访问g()
,返回2 + 3 => 5
这在几种情况下很有用.例如,如果我有一个接受大量参数的函数,但只有少数对我有用,我可以像这样写一个泛型函数:
def many_arguments(a, b, c, d, e, f, g, h, i): return # SOMETHING def curry(function, **curry_args): # call is a closure which closes over the environment of curry. def call(*call_args): # Call the function with both the curry args and the call args, returning # the result. return function(*call_args, **curry_args) # Return the closure. return call useful_function = curry(many_arguments, a=1, b=2, c=3, d=4, e=5, f=6)
useful_function
现在是一个只需要3个参数而不是9个参数的函数.我避免重复自己,并且还创建了一个通用的解决方案; 如果我写另一个多参数函数,我可以curry
再次使用该工具.
通常情况下,如果一个人没有闭包,那么必须定义一个类来携带它与闭包的环境相当,并传递它.
例如,在像Lisp这样的语言中,可以定义一个函数,该函数返回一个函数(具有一个封闭的环境),从而为其参数添加一些预定义的数量:
(defun make-adder (how-much) (lambda (x) (+ x how-much)))
并像这样使用它:
cl-user(2): (make-adder 5) #cl-user(3): (funcall * 3) ; calls the function you just made with the argument '3'. 8
在没有闭包的语言中,你会做这样的事情:
public class Adder { private int howMuch; public Adder(int h) { howMuch = h; } public int doAdd(int x) { return x + howMuch; } }
然后像这样使用它:
Adder addFive = new Adder(5); int addedFive = addFive.doAdd(3); // addedFive is now 8.
关闭隐含地带有它的环境; 您可以从执行部分(lambda)内部无缝地引用该环境.如果没有闭包,您必须明确环境.
这应该向你解释什么时候使用闭包:所有的时间.大多数实例,其中一个类被实例化以携带一些来自计算的另一部分的状态并将其应用于其他地方,这些实例被支持它们的语言中的闭包优雅地取代.
可以实现具有闭包的对象系统.