如何告诉对象执行消息

Mug*_*gen 4 message smalltalk squeak

我有一个对象,以及一个包含我想发送给它的消息的字符串.

例如,字符串'+ 5',我想发送给某个整数对象.

如果它在工作区中,那么我只会写"obj + 5",但我需要在运行时完成,而不事先知道字符串...

Ber*_*erg 12

如果您可以将消息的参数与消息本身分开,那么您可以"执行"消息发送:

obj := 3.
msg := '+'.
arg := 5.
result := obj perform: msg asSymbol with: arg.
Run Code Online (Sandbox Code Playgroud)

否则,您将不得不使用编译器,它将字符串转换为已编译的代码并执行它:

obj := 3.
msg := 'self + 5'.
result := Compiler evaluate: msg for: obj logged: false.
Run Code Online (Sandbox Code Playgroud)

避免重复编译的常用技术是编译块,可以更有效地进行评估:

obj := 3.
msg := '[:x | x + 5]'.
block := Compiler evaluate: msg.
result := block value: obj.
Run Code Online (Sandbox Code Playgroud)

顺便说一句,上面(和下面)的代码是针对Squeak的,其他Smalltalks可能有不同的方式来访问编译器.

有一种更加强硬的方式可以直接从字符串中访问变量.这是通过在"thisContext"中执行已编译的代码(在这种情况下,您甚至需要在工作空间中声明临时变量):

| obj msg result |
obj := 3.
msg := 'obj + 5'.
result := Compiler new evaluate: msg in: thisContext to: nil.
Run Code Online (Sandbox Code Playgroud)

但是,我不推荐这最后一种技术.执行通常比涉及编译器更安全.也就是说,它可以用来实现一些严肃的元东西.例如:

| obj |
obj := 3.
'The result is {obj + 5}.' expand
Run Code Online (Sandbox Code Playgroud)

"扩展"方法的实施留给了好奇的读者;)