我目前正在研究Smalltalk。
是否可以在变量内存储函数或方法?
例如,在Python中,人们可能会说:
x = someobject.method
x() # calling it
在Smalltalk中这可能吗?将something.method
本身作为参数传递给另一种方法怎么办?
答案 0 :(得分:4)
您可以通过向类对象询问具有给定名称的方法来获得方法对象。 >>
下面是一条消息,该消息以方法名称作为参数发送到类Object
。
Object >> #asString
这将返回类型为CompiledMethod
的实例。这是表示方法的对象。像任何对象一样,您可以将其存储在变量中。
copyMethod := Object>>#asString.
例如,如果您在Pharo a Playground中打开并查看上面的代码,则会得到:
然后可以使用消息#valueWithReceiver:arguments:
执行该方法。这需要接收者(自身/本)和可能的参数作为参数。
result := copyMethod
valueWithReceiver: Object new arguments: #().
但是,这是执行方法的底层方法。
我会说更常见的是直接在对象上执行具有给定名称的方法。可以使用perform:
或perform:withArguments:
完成。您可以使用方法名称作为参数将其发送给对象
receiver := Object new.
receiver perform: #asString.
上面的代码在接收器对象上执行名为asString
的方法。这通常用于传递我们需要执行的方法的名称。区别在于CompiledMethod
的实例是不可变的。如果更改该方法的代码,则会创建一个新实例,并且最终可以执行该方法的旧版本。
答案 1 :(得分:1)
通常,您在Smalltalk中要做的就是发送消息。您永远不会执行方法,因为它违反了封装并且通常不是正确的抽象级别。
发送消息时,在其对象类methodDictionary中查找接收器对象以将CompiledMethod与消息选择器相关联,如果没有,则在超类methodDictionary中进行查找,依此类推...或者最后发送dosNotUnderstand:消息(如果没有相应方法)被发现。所有这些机制都是在VM中执行的。这不是程序员的工作。
要发送变量消息时,可以使用perform:
perform:with:
perform:withArgument:
,如@ andrei-chis所述。
selector:= #(printString storeString asString) at: index.
^self perform: selector
要允许访问低级机器,我们可以通过发送消息valueWithReceiver:arguments:
直接调用该方法,但是我强烈建议不要使用它。正如我说的,不是正确的抽象级别-除非您试图在Smalltalk VM之上实现另一种语言并寻求这种低级别的构造。
如果您忽略了此警告,则您有责任提供作为接收者的正确类的实例(或者,如果您想破解,至少要为对象提供足够的空间来分配实例变量等)。 。这样做的失败最少,并且您可以破坏对象内存并使VM早晚崩溃,如果在致命崩溃之前有时间保存损坏的映像,则可以松散一些工作...
因此,一句话,请考虑将消息发送到对象而不是调用方法;让对象自己决定执行哪种方法,这不关我们的事,Smalltalk一直是消息。