有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
当前回答
概念与上面描述的相同,但如果您有PHP背景,则使用PHP代码进一步解释。
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });
函数($v){返回$v > 2}是lambda函数定义。我们甚至可以将它存储在一个变量中,这样它就可以被重用:
$max = function ($v) { return $v > 2; };
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);
现在,如果您想更改筛选数组中允许的最大数量,该怎么办?你必须编写另一个lambda函数或创建一个闭包(PHP 5.3):
$max_comp = function ($max) {
return function ($v) use ($max) { return $v > $max; };
};
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));
闭包是在自己的环境中求值的函数,该环境具有一个或多个绑定变量,在调用该函数时可以访问这些变量。它们来自函数式编程领域,其中有许多概念。闭包类似于lambda函数,但更聪明的地方在于它们能够与定义闭包的外部环境中的变量进行交互。
下面是一个简单的PHP闭包示例:
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };
$closure();
这篇文章解释得很好。
其他回答
并不是所有的闭包都是lambdas,也不是所有的lambdas都是闭包。两者都是函数,但不一定是以我们习惯的方式。
lambda本质上是一个内联定义的函数,而不是声明函数的标准方法。lambda可以经常作为对象传递。
闭包是一种函数,它通过引用其主体外部的字段来封闭其周围的状态。封闭状态在闭包调用之间保持不变。
在面向对象语言中,闭包通常是通过对象提供的。然而,一些面向对象语言(如c#)实现的特殊功能更接近于纯函数式语言(如lisp)所提供的闭包的定义,后者没有对象来封装状态。
有趣的是,在c#中引入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;
};
}
这个问题已经12年了,我们仍然把它作为谷歌中“闭包vs lambda”的第一个链接。 所以我不得不说,因为没有人明确地说过。
Lambda表达式是一个匿名函数(声明)。
一个闭包,引用Scott的《编程语言语用学》解释为:
创建引用环境的显式表示(通常是当前调用子例程时执行的环境),并将其与子例程的引用捆绑在一起,称为闭包。
也就是说,它就像我们所说的“函数+投降上下文”的捆绑。
简单地说,闭包是一个关于作用域的技巧,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无关——它们是两个不同(尽管相关)的概念。