java闭包和lambda关系_'闭包'和'lambda'有什么区别?

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

现在我们在这里,它们与常规功能有什么不同?

#1楼

并非所有的闭包都是lambda,并非所有的lambd都是闭包。 两者都是功能,但不一定是我们习惯了解的方式。

lambda本质上是一个内联定义的函数,而不是声明函数的标准方法。 Lambdas经常可以作为对象传递。

闭包是一种通过引用其主体外部的字段来包围其周围状态的函数。 封闭状态保持在闭包的调用之间。

在面向对象的语言中,闭包通常通过对象提供。 但是,某些OO语言(例如C#)实现的特殊功能更接近于纯函数语言 (如lisp)提供的闭包定义,这些闭包没有包含状态的对象。

有趣的是,在C#中引入Lambdas和Closures使函数式编程更接近主流使用。

#2楼

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

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;

};

}

#3楼

lambda只是一个匿名函数 - 一个没有名称的函数。 在某些语言中,例如Scheme,它们等同于命名函数。 实际上,函数定义被重写为在内部将lambda绑定到变量。 在其他语言中,如Python,它们之间存在一些(相当不必要的)区别,但它们的行为方式相同。

闭包是关闭定义它的环境的任何函数。 这意味着它可以访问不在其参数列表中的变量。 例子:

def func(): return h

def anotherfunc(h):

return func()

这将导致错误,因为func不会关闭 anotherfunc的环境 - h未定义。 func只关闭全局环境。 这将有效:

def anotherfunc(h):

def func(): return h

return func()

got closures correct (mutation still doesn't work), this means that it closes over anotherfunc 's environment and can access variables inside of it. 因为在这里, func在anotherfunc定义,并且在python 2.3及更高版本(或者像这样的一些数字)中,当它们闭包正确时(变异仍然不起作用),这意味着它关闭了 anotherfunc的环境并且可以访问里面的变量。 在Python 3.1+中,使用nonlocal关键字时,变异也起作用。

另一个重要的一点- func将继续关闭了anotherfunc ,即使它不再在评估的环境anotherfunc 。 此代码也适用:

def anotherfunc(h):

def func(): return h

return func

print anotherfunc(10)()

这将打印10。

正如您所注意到的,这与lambda无关 - 它们是两个不同的(虽然相关)概念。

#4楼

从编程语言的角度来看,它们完全是两回事。

基本上对于图灵完整语言我们只需要非常有限的元素,例如抽象,应用和缩减。 抽象和应用程序提供了构建lamdba表达式的方法,并且减少了lambda表达式的含义。

Lambda提供了一种可以抽象出计算过程的方法。 例如,为了计算两个数的和,可以抽象出取两个参数x,y和返回x + y的过程。 在方案中,您可以将其编写为

(lambda (x y) (+ x y))

您可以重命名参数,但它完成的任务不会更改。 在几乎所有编程语言中,您都可以为lambda表达式指定名称,这些名称是命名函数。 但是没有太大的区别,它们在概念上可以被认为只是语法糖。

好的,现在想象一下如何实现这一点。 每当我们将lambda表达式应用于某些表达式时,例如

((lambda (x y) (+ x y)) 2 3)

我们可以简单地用要评估的表达式替换参数。 这个模型已经非常强大了。 但是这个模型不能让我们改变符号的值,例如我们无法模仿状态的变化。 因此,我们需要一个更复杂的模型。 为了简化,每当我们想要计算lambda表达式的含义时,我们将符号对和相应的值放入环境(或表)中。 然后通过查找表中的相应符号来评估其余(+ xy)。 现在,如果我们提供一些原语来直接对环境进行操作,我们可以对状态的变化进行建模!

在此背景下,检查此功能:

(lambda (x y) (+ x y z))

我们知道,当我们评估lambda表达式时,xy将被绑定在一个新表中。 但是我们如何以及在哪里可以看到z? 实际上,z被称为自由变量。 必须有一个包含z的外部环境。 否则,只能通过绑定x和y来确定表达式的含义。 为清楚起见,您可以在方案中编写如下内容:

((lambda (z) (lambda (x y) (+ x y z))) 1)

所以z将在外表中绑定为1。 我们仍然得到一个接受两个参数的函数,但它的真正含义还取决于外部环境。 换句话说,外部环境关闭了自由变量。 在set!的帮助下,我们可以使函数有状态,即它不是数学意义上的函数。 它返回的不仅取决于输入,还取决于z。

这是你已经非常了解的东西,对象的方法几乎总是依赖于对象的状态。 这就是为什么有些人说“闭包是穷人的对象。”但我们也可以认为对象是穷人的封闭,因为我们真的喜欢一流的功能。

我使用方案来说明由于该方案是最早的具有真正闭包的语言之一的想法。 这里的所有材料都更好地呈现在SICP第3章中。

总而言之,lambda和闭包是非常不同的概念。 lambda是一个函数。 闭包是一对lambda和关闭lambda的相应环境。

#5楼

它就像这样简单:lambda是一种语言结构,即简单函数的语法; 闭包是一种实现它的技术 - 或任何一流的函数,就此而言,命名或匿名。

更准确地说,闭包是在运行时如何表示第一类函数 ,作为一对“代码”和一个环境“关闭”该代码中使用的所有非局部变量。 这样,即使已经退出它们的外部范围,这些变量仍然可以访问。

不幸的是,有许多语言不支持作为一等值的函数,或者只支持它们的残缺形式。 所以人们经常使用“闭合”这个词来区分“真实的东西”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值