2011-06-12 14 views

cevap

7

Evet, Smalltalk'ın kapanmaları var.

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

Kapaklar, örneği geçti etrafında ve manipüle edilebilir nesnelerdir: Aşağıdaki kod iki argümanının toplamını döndüren bir kapatma oluşturur. Eğer value, value:, value:value: göndermek bir kapatma ... değerlendirmek

sum value: 1 value: 2. 

Kapaklar belirgin yinelemenizi koleksiyonları, filtre, harita, ... bir koleksiyonun tüm değerleri ile kullanılır:

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

Dahası, döngüler gibi kontrol yapılar için kullanılır:

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

da koşul uygulanmaktadır kullanılarak kilitler:

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

İlk örneğiniz yalnızca "value: value:" iletisiyle sağlanan parametreleri alır, ancak 'whileTrue:' örneğiniz, bloğun dışında tanımlanmış olan 'yineleyici' değişkenini kullanan bloklara sahiptir. Bir lambda ve diğeri bir kapanış mı, yoksa Smalltalk'ta bir fark yok mu? – quamrana

+0

@quamrana: (Görünür) fark yoktur. Smalltalk uygulamalarının çoğu, dış değişkenlerin kullanımına bağlı olarak kapatma nesnelerini optimize eder. Tüm kapaklar aynı mesajları anlar, böylece bir geliştirici olarak sizin için hiçbir fark yoktur. –

5

Pharo onlara sahip:

tüm VM kapatma desteği son görüntüleri

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

İade 5 için gerekli var.

Ama dikkat ederseniz

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

çalışmaz (Cannot store into ->init …), CL (örneğin) gibi: Ben yanılmıyorsam

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

, bundan önce çalışmak için kullanılan yeni kapatma derleyicisi tanıtıldı. Yeni derleyici ile neden çalışmadığından emin değilim.

+4

Blok ve yöntem argümanları Smalltalk'ta salt okunurdur. Bazı eski derleyiciler blok argüman yazıyor olsa da düzgün kontrol etmedi. –

+0

Açıklama için teşekkürler, Lukas! – danlei

+1

Ancak, şu gibi bir blok yerel temp kullanabilirsiniz: makeCounter: = [: init | | saymak | saymak: = init. [sayım: = say + 1 sayım]]. (makeCounter değeri: 3) değeri; değer –