您可以将函数存储在变量中吗?

时间:2019-05-03 11:59:35

标签: methods message smalltalk

我目前正在研究Smalltalk。

是否可以在变量内存储函数或方法?

例如,在Python中,人们可能会说:

x = someobject.method
x() # calling it

在Smalltalk中这可能吗?将something.method本身作为参数传递给另一种方法怎么办?

2 个答案:

答案 0 :(得分:4)

您可以通过向类对象询问具有给定名称的方法来获得方法对象。 >>下面是一条消息,该消息以方法名称作为参数发送到类Object

Object >> #asString

这将返回类型为CompiledMethod的实例。这是表示方法的对象。像任何对象一样,您可以将其存储在变量中。

copyMethod := Object>>#asString.

例如,如果您在Pharo a Playground中打开并查看上面的代码,则会得到:

executing code in playground

然后可以使用消息#valueWithReceiver:arguments:执行该方法。这需要接收者(自身/本)和可能的参数作为参数。

result := copyMethod 
    valueWithReceiver: Object new arguments: #().

executing the method

但是,这是执行方法的底层方法。

我会说更常见的是直接在对象上执行具有给定名称的方法。可以使用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一直是消息。