1

それを行うより良い方法はありますか:

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

?

編集このコードは単なる例であり、次のようなものはどうですか:

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

checkSomethingElse の代わりに checkAnotherThing が必要な場所。

また:

[:oneParameter :anotherParameter | 
    oneParameter doSomethingWith: anotherParameter]

ここで、3 番目のパラメーターを追加します。

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

3 に答える 3

2

もちろん、リフレクションを使用してブロックを操作することもできますが、最もクリーンな解決策は、ブロックを別のブロックでラップすることにより、ブロック内の値を動的にバインドすることです。

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

factory、aとbが異なる値にバインドされているブロックを生成します。

aBlock := factory value: 3 value: 2.

aBlock回答の評価5

于 2011-04-20T20:00:14.063 に答える
2

ブロックを文字列としてシリアライズし、文字列操作を行うことは便利ですが、ブロックの内容を明確に把握していない場合は非常に危険です。

ブロックの 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 の変更されたコピーを作成していることに注意してください。

原則はより一般的に適用されます: ブロックを逆コンパイルし、操作を行い (たとえば、一連のメッセージ送信の途中でセレクターを変更します)、新しい解析ツリーをコンパイルします。(印刷されたツリーを評価するのではなく、ツリーを直接コンパイルする方法はわかりませんが、方法があると確信しています。)

(注意: 上記は Squeak で書いたものです。Pharo の新しいコンパイラである Opal でのプレイ状況がわからないので、Pharo では少し違うことをするかもしれません。)

于 2011-04-21T07:59:41.970 に答える
2
In Pharo:

| aBlock   x |

x := 1.

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

Transcript show: aBlock value printString; cr.

x := 41.

Transcript show: aBlock value printString; cr.
于 2011-04-20T12:36:09.630 に答える