2011-06-12 94 views

回答

7

是的,Smalltalk已关闭。下面的代码创建一个返回其两个参数之和的闭包:

sum := [ :a :b | a + b ]. 

闭包是可实例化,传递和操纵的对象。为了评估您发送valuevalue:value:value:,封闭...

sum value: 1 value: 2. 

瓶盖醒目地与集合迭代,过滤器,地图,...一个集合的所有值使用:

aCollection select: [ :each | each isOdd ]. 
aCollection inject: 0 into: [ :each :result | each + result ]. 

此外,它们可用于控制结构样环:

[ iterator hasNext ] 
    whileTrue: [ iterator next ]. 
1 to: 10 do: [ :each | ... ]. 

使用封闭件还条件语句实现:

condition 
    ifTrue: [ do this ] 
    ifFalse: [ do that ] 
+0

您的第一个示例只接受'value:value:'消息提供的参数,但您的'whileTrue:'示例具有使用在块外部定义的变量'iterator'的块。一个是lambda,另一个是闭包,还是在Smalltalk中没有区别? – quamrana 2011-06-12 18:18:31

+0

@quamrana:没有(可见的)区别。大多数Smalltalk实现根据外部变量的使用来优化它们的闭包对象。尽管所有关闭都能理解相同的消息,所以对于开发者来说,没有任何区别。 – 2011-06-13 08:50:08

5

Pharo有他们:

所有虚拟机有封闭性的支持需要 的最新图像

makeAdder := [ :x | [ :y | x + y ]]. 
add2 := makeAdder value: 2. 
add2 value: 3. 

返回5

但是请注意,

makeCounter := [ :init | [ init := init + 1. init ]]. 

将无法​​正常工作(Cannot store into ->init …),如(例如)在CL:

CL-USER> ((lambda (init) (lambda() (incf init))) 0) 
#<COMPILED-LEXICAL-CLOSURE #xC7A495E> 
CL-USER> (funcall *) 
1 
CL-USER> (funcall **) 
2 
CL-USER> (funcall ***) 
3 

如果我没有记错,这使用之前的工作引入了新的闭包编译器。我不确定为什么它不适用于新的编译器。

+4

块和方法参数在Smalltalk中是只读的。尽管如此,一些古代编译器没有正确检查块参数写入。 – 2011-06-13 08:57:47

+0

感谢您的澄清,卢卡斯! – danlei 2011-06-15 14:25:28

+1

但您可以使用块本地temp,如下所示: makeCounter:= [:init | | count | count:= init。 [count:= count + 1. count]]。 (makeCounter value:3)value;值 – 2016-04-04 22:38:24