Изменение содержимого замыкания - PullRequest
1 голос
/ 20 апреля 2011

Есть ли лучший способ сделать это, чем:

|aBlock|
aBlock := [3+2].
aBlock := Object readFrom: (a printString copyReplaceAll: '3' with: '2').

?

РЕДАКТИРОВАТЬ Этот код был просто примером, как насчет таких вещей, как:

[:something | 
    something checkSomethingElse ifNil: 
        [whatever] 
    ifNotNil:
        [something getSomethingDone]]

Где сейчас я хочу проверитьAnotherThing вместо checkSomethingElse.

или:

[:oneParameter :anotherParameter | 
    oneParameter doSomethingWith: anotherParameter]

Где сейчас я хочу добавить третий параметр и:

[:oneParameter :anotherParameter :yetAnotherParameter | 
    oneParameter doSomethingWith: anotherParameter and: yetAnotherParameter]

Ответы [ 3 ]

2 голосов
/ 21 апреля 2011

Конечно, вы можете использовать отражение для манипулирования блоками, но самое чистое решение - динамически связывать значения в вашем блоке, заключая его в другой блок:

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

factory создает блоки, где a и b связаны с различными значениями:

aBlock := factory value: 3 value: 2.

Оценка aBlock ответов 5.

2 голосов
/ 21 апреля 2011

Сериализация блока как строки и выполнение строковых манипуляций, хотя и удобно, также довольно опасно, если у вас нет четкого представления о содержимом блока.

Звучит так, как если бы выхотелось бы иметь возможность манипулировать AST блока - дать блок, разобрать его, изменить структуру (в данном случае заменить литерал), а затем скомпилировать измененную структуру.Для этого вы можете сделать что-то вроде этого:

| aBlock ast |
aBlock := [3+2].
ast := aBlock decompile.
ast statements first receiver: (DecompilerConstructor new codeAnyLiteral: 4).
aBlock := (Compiler evaluate: ast printString) first.
aBlock value. "==> 6"

Обратите внимание, что мы на самом деле не изменяем aBlock, а создаем мутированную копию aBlock.

Этот принцип применяется в более общем плане: декомпилировать блок, выполнить манипуляции (например, изменить селектор на полпути по цепочке отправок сообщений), скомпилировать новое дерево разбора.(Я не знаю, как из рук в руки компилировать дерево напрямую , а не оценивать распечатанное дерево, но я уверен, что есть способ.)

(Предостережение: I 'Вы написали выше в Squeak. Я не знаю, как обстоят дела с Opal, новым компилятором Pharo, так что, возможно, в Pharo вы сделаете что-то немного другое.)

2 голосов
/ 20 апреля 2011
In Pharo:

| aBlock   x |

x := 1.

aBlock := [ x := x + 1].

Transcript show: aBlock value printString; cr.

x := 41.

Transcript show: aBlock value printString; cr.
...