2011-06-12 15 views

Respuesta

7

Sí, Smalltalk tiene cierres. El siguiente código crea un cierre que devuelve la suma de sus dos argumentos:

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

Los cierres son objetos que se pueden crear instancias, pasan alrededor y manipulados. Para evaluar un cierre que envíe value, value:, value:value:, ...

sum value: 1 value: 2. 

Los cierres se utilizan prominentemente con las colecciones de ITERATE filtro, mapas, ... todos los valores de una colección:

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

Además, se utilizan para las estructuras de control como bucles:

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

también condicionales se implementan utilizando cierres:

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

Su primer ejemplo solo toma los parámetros proporcionados por el mensaje 'value: value:', pero su ejemplo de 'whileTrue:' tiene bloques que usan la variable 'iterator' que se define fuera del bloque. ¿Una es una lambda y la otra un cierre, o no hay diferencia en Smalltalk? – quamrana

+0

@quamrana: No hay diferencia (visible). La mayoría de las implementaciones Smalltalk optimizan sus objetos de cierre dependiendo del uso de variables externas. Sin embargo, todos los cierres comprenden los mismos mensajes, por lo que para usted como desarrollador no hay diferencia. –

5

Pharo ellos tiene:

todas las máquinas virtuales tienen el apoyo de cierre necesaria para últimas imágenes

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

Devoluciones 5.

notar que

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

no va a funcionar (Cannot store into ->init …), como (por ejemplo) en la 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 

Si no me equivoco, esto solía trabajar antes de la Se introdujo un nuevo compilador de cierre. No estoy seguro de por qué no funciona con el nuevo compilador.

+4

Los argumentos de bloque y método son de solo lectura en Smalltalk. Sin embargo, algunos compiladores antiguos no revisaron correctamente las escrituras de argumentos en bloque. –

+0

Gracias por la aclaración, Lukas! – danlei

+1

Pero puede usar un bloque de temperatura local, así: makeCounter: = [: init | | contar | count: = init. [count: = count + 1. count]]. (valor de valor de contador: 3); valor –