2011-06-12 8 views

Odpowiedz

7

Tak, Smalltalk ma zamknięcia. Poniższy kod tworzy zamknięcie zwracającą sumę dwóch argumentów:

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

zamknięcia są obiekty, które mogą być instancja, mijały się i manipulować. Aby ocenić zamknięcie wysyłaniu value, value:, value:value: ...

sum value: 1 value: 2. 

Zamknięcia są wyraźnie stosowane w kolekcjach iteracyjne, filtr, Mapa, ... wszystkie wartości kolekcji:

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

Ponadto, są one wykorzystywane do struktur kontrolnych jak pętle:

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

także warunkowe są realizowane za pomocą zamknięć:

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

Twój pierwszy przykład przyjmuje tylko parametry dostarczone przez komunikat 'value: value:', ale twój przykład 'whileTrue:' ma bloki, które używają zmiennej 'iterator', która jest zdefiniowana poza blokiem. Czy jedno jest lambdą, a drugie zamknięciem, czy też nie ma różnicy w Smalltalk? – quamrana

+0

@quamrana: Nie ma żadnej widocznej różnicy. Większość wdrożeń Smalltalk optymalizuje ich obiekty zamykające w zależności od użycia zmiennych zewnętrznych. Wszystkie zamknięcia rozumieją te same wiadomości, więc dla ciebie jako programisty nie ma różnicy. –

5

Pharo je ma:

wszystkie maszyny wirtualne mają wsparcie zamknięcie wymagane najnowsze obrazy

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

Zwraca 5.

jednak zauważyć, że

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

nie zadziała (Cannot store into ->init …), jak (na przykład) w 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 

Jeśli się nie mylę, to używane do pracy przed wprowadzono nowy kompilator zamknięcia. Nie jestem pewien, dlaczego nie działa z nowym kompilatorem.

+4

Argumenty bloku i metody są tylko do odczytu w Smalltalk. Niektóre starsze kompilatory nie sprawdzały jednak poprawnie pod kątem argumentów blokowych. –

+0

Dzięki za wyjaśnienia, Lukas! – danlei

+1

Ale możesz użyć bloku lokalnego, takiego jak ten: makeCounter: = [: init | | liczyć | count: = init. [count: = count + 1. count]]. (makeCounter wartość: 3) wartość; wartość –