2011-06-12 2 views

ответ

7

Да, у Smalltalk есть затворы. Следующий код создает замыкание, которое возвращает сумму двух аргументов:

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

Затворы объекты, которые могут быть созданы, прошли вокруг и манипулируют. Для того, чтобы оценить замыкание вы отправляете value, value:, 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

Ваш первый пример принимает только параметры, предоставленные сообщением 'значение: значение:', но ваш пример 'whileTrue:' содержит блоки, в которых используется переменная 'iterator', которая определена вне блока. Является ли один лямбда, а другой закрытием, или нет никакой разницы в Smalltalk? – quamrana

+0

@quamrana: Нет (видимой) разницы. Большинство реализаций Smalltalk оптимизируют свои объекты замыкания в зависимости от использования внешних переменных. Все блокировки понимают одни и те же сообщения, хотя для вас, как разработчика, нет никакой разницы. –

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. Однако некоторые древние компиляторы не проверяли правильность записи блоков. –

+0

Спасибо за разъяснение, Лукас! – danlei

+1

Но вы можете использовать локальную температуру блока, например: makeCounter: = [: init | | счет | count: = init. [count: = count + 1. count]]. (значение makeCounter: 3); стоимость –

Смежные вопросы