有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
当前回答
这个问题很老了,有很多答案。 现在有了Java 8和官方Lambda这两个非官方的闭包项目,这个问题又重新出现了。
Java上下文中的答案(通过Lambdas和闭包-有什么区别?):
闭包是一个lambda表达式,它与一个环境配对,将它的每个自由变量绑定到一个值。在Java中,lambda表达式将通过闭包的方式实现,因此这两个术语在社区中可以互换使用。”
其他回答
简单地说,闭包是一个关于作用域的技巧,lambda是一个匿名函数。我们可以用lambda更优雅地实现闭包,lambda经常被用作传递给更高函数的参数
lambda只是一个匿名函数——一个没有名字定义的函数。在Scheme等某些语言中,它们等同于命名函数。实际上,函数定义在内部被重写为将lambda绑定到变量。在其他语言中,如Python,它们之间有一些(相当不必要的)区别,但它们在其他方面的行为是相同的。
闭包是在定义它的环境上关闭的任何函数。这意味着它可以访问不在其参数列表中的变量。例子:
def func(): return h
def anotherfunc(h):
return func()
这将导致一个错误,因为func不会在另一个环境中关闭func - h是undefined。Func只在全局环境下关闭。这是可行的:
def anotherfunc(h):
def func(): return h
return func()
因为这里,func是在anotherfunc中定义的,而在python 2.3及以上版本(或类似这样的数字)中,当他们几乎正确地获得闭包时(突变仍然无效),这意味着它在anotherfunc的环境中关闭,并可以访问其中的变量。在Python 3.1+中,使用nonlocal关键字时也可以使用突变。
还有一点很重要——func将继续在另一个func的环境中关闭,即使它不再在另一个func中被求值。这段代码也可以工作:
def anotherfunc(h):
def func(): return h
return func
print anotherfunc(10)()
这将输出10。
正如您所注意到的,这与lambda无关——它们是两个不同(尽管相关)的概念。
Lambda是一个匿名函数定义,它(不一定)绑定到标识符。
“匿名函数起源于阿朗佐·丘奇(Alonzo Church)发明的lambda微积分,其中所有函数都是匿名的”——维基百科
闭包是lambda函数的实现。
Peter J. Landin在1964年将闭包定义为拥有一个环境部分和一个控制部分,由他的SECD机器用于计算表达式
Lambda和闭包的一般解释在其他响应中涵盖。
对于c++背景的人来说,Lambda表达式是在c++ 11中引入的。可以把Lambdas看作是一种创建匿名函数和函数对象的方便方法。
"The distinction between a lambda and the corresponding closure is precisely equivalent to the distinction between a class and an instance of the class. A class exists only in source code; it doesn’t exist at runtime. What exists at runtime are objects of the class type. Closures are to lambdas as objects are to classes. This should not be a surprise, because each lambda expression causes a unique class to be generated (during compilation) and also causes an object of that class type, a closure to be created (at runtime)." - Scott Myers
c++允许我们检查Lambda和Closure之间的细微差别,因为您必须显式地指定要捕获的自由变量。
在下面的示例中,Lambda表达式没有自由变量,是一个空捕获列表([])。它本质上是一个普通函数,严格意义上不需要闭包。所以它甚至可以作为函数指针参数传递。
void register_func(void(*f)(int val)) // Works only with an EMPTY capture list
{
int val = 3;
f(val);
}
int main()
{
int env = 5;
register_func( [](int val){ /* lambda body can access only val variable*/ } );
}
只要在捕获列表([env])中引入了来自周围环境的自由变量,就必须生成一个Closure。
register_func( [env](int val){ /* lambda body can access val and env variables*/ } );
由于这不再是一个普通的函数,而是一个闭包,因此会产生编译错误。 不存在从"lambda []void (int val)->void"到"void (*)(int val)"的合适转换函数
这个错误可以用函数包装器std::function来修复,它接受任何可调用的目标,包括生成的闭包。
void register_func(std::function<void(int val)> f)
有关c++示例的详细解释,请参阅Lambda和闭包。
Lambda表达式只是一个匿名函数。例如,在纯java中,你可以这样写:
Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
public Job apply(Person person) {
Job job = new Job(person.getPersonId(), person.getJobDescription());
return job;
}
};
其中Function类是在java代码中构建的。现在你可以在某处调用mapPersonToJob.apply(person)来使用它。这只是一个例子。在没有语法之前,这是一个lambda。lambda是一个捷径。
关闭:
当Lambda可以访问此作用域之外的变量时,它就成为闭包。我猜你可以说它的魔力,它神奇地包裹着它被创建的环境,并使用其作用域之外的变量。因此,闭包意味着lambda可以访问它的OUTER SCOPE。
在Kotlin中,lambda总是可以访问它的闭包(在它的外部作用域中的变量)
Lambda vs闭包
是匿名函数(方法)
闭包是封闭(捕获)其封闭范围内的变量的函数。非本地变量)
Java
interface Runnable {
void run();
}
class MyClass {
void foo(Runnable r) {
}
//Lambda
void lambdaExample() {
foo(() -> {});
}
//Closure
String s = "hello";
void closureExample() {
foo(() -> { s = "world";});
}
}
斯威夫特(结束)
class MyClass {
func foo(r:() -> Void) {}
func lambdaExample() {
foo(r: {})
}
var s = "hello"
func closureExample() {
foo(r: {s = "world"})
}
}