有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。

现在我们到了这里,它们和普通函数有什么不同?


当前回答

这个问题很老了,有很多答案。 现在有了Java 8和官方Lambda这两个非官方的闭包项目,这个问题又重新出现了。

Java上下文中的答案(通过Lambdas和闭包-有什么区别?):

闭包是一个lambda表达式,它与一个环境配对,将它的每个自由变量绑定到一个值。在Java中,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总是可以访问它的闭包(在它的外部作用域中的变量)

概念与上面描述的相同,但如果您有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();

这篇文章解释得很好。

这个问题已经12年了,我们仍然把它作为谷歌中“闭包vs lambda”的第一个链接。 所以我不得不说,因为没有人明确地说过。

Lambda表达式是一个匿名函数(声明)。

一个闭包,引用Scott的《编程语言语用学》解释为:

创建引用环境的显式表示(通常是当前调用子例程时执行的环境),并将其与子例程的引用捆绑在一起,称为闭包。

也就是说,它就像我们所说的“函数+投降上下文”的捆绑。

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无关——它们是两个不同(尽管相关)的概念。

当大多数人想到函数时,他们想到的是命名函数:

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;
           };
 }