有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
当前回答
闭包意味着一个函数返回另一个函数。不是结果,而是像委托一样的可调用函数。 Lambda是一个匿名函数描述。如果lambda返回一个函数,它也可以是一个闭包。
其他回答
当大多数人想到函数时,他们想到的是命名函数:
function foo() { return "This string is returned from the 'foo' function"; }
当然,这些都是按名字命名的:
foo(); //returns the string above
使用lambda表达式,你可以有匿名函数:
@foo = lambda() {return "This is returned from a function without a name";}
在上面的例子中,你可以通过赋值的变量来调用lambda:
foo();
然而,比将匿名函数分配给变量更有用的是将它们传递给或从高阶函数传递,即接受/返回其他函数的函数。在很多情况下,命名一个函数是不必要的:
function filter(list, predicate)
{ @filteredList = [];
for-each (@x in list) if (predicate(x)) filteredList.add(x);
return filteredList;
}
//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)});
闭包可以是命名函数或匿名函数,但当它“关闭”函数定义范围内的变量时,即闭包仍将引用闭包本身中使用的任何外部变量的环境。这是一个命名闭包:
@x = 0;
function incrementX() { x = x + 1;}
incrementX(); // x now equals 1
这看起来并不多,但如果这都是在另一个函数中,你将incrementX传递给一个外部函数呢?
function foo()
{ @x = 0;
function incrementX()
{ x = x + 1;
return x;
}
return incrementX;
}
@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)
这就是在函数式编程中获得有状态对象的方法。因为不需要命名“incrementX”,你可以在这种情况下使用lambda:
function foo()
{ @x = 0;
return lambda()
{ x = x + 1;
return x;
};
}
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"})
}
}
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表达式是无状态的,因为它依赖于参数、内部变量或常量来执行操作。 函数<Integer,Integer> lambda = t -> { Int n = 2 返回t * n } 闭包保持状态,因为它使用外部变量(即函数体范围之外定义的变量)以及参数和常量来执行操作。 Int n = 2 函数<Integer,Integer>闭包= t -> { 返回t * n }
当Java创建闭包时,它将变量n与函数一起保存,以便在传递给其他函数或在任何地方使用时可以引用它。