smalltalk 新建和初始化的区别

问题描述 投票:0回答:2

我有以下三个代码片段(在 Pharo 中运行),我想了解以下代码为何以及如何(不)理解 new 和初始化

a := Point initialize.
这不会产生错误,但是在检查它时,类 Point 不会将任何 x 和 y 变量初始化为 nil (为什么?)

a := Point.
a x: 5 y:6.

这有效,产生向量 5@6。为什么调用点的时候不需要调用new呢

a := Point new.
a x:5 y:6.

这不起作用,会产生错误。为什么?见上文

smalltalk
2个回答
3
投票

Smalltalk 中的一个关键(但有些令人困惑)的想法是,有与实例关联的方法,也有与类关联的方法。这很令人困惑,因为您需要跟踪是否正在向(或“调用”)实例方法或类方法发送消息。 (Pharo 系统浏览器有一对“Inst. side”和“Class side”单选按钮。)

在第一个示例中,

Pharo initialize
您正在调用class
initialize
方法(并且由于Point的类侧没有实现,因此它执行在Object的类侧找到的方法)。重要的是,为了您的目的,初始化方法隐式地回答 self,接收者,即 Point 类。

在第二个示例中,您将对 Point 类的引用存储在变量

a
中。请注意,这不是一个新对象,而只是对现有(Point 类)对象的另一个引用。在下一行中,您将消息
x:y:
发送到 Point 类。如果您查看
x:y:
的类端实现,您会发现它调用
basicNew
来应答 Point 的新 instance,然后将消息
setX:setY:
发送到该 instance。如果您查看 Point 实例侧的
setX:setY:
实现,您会发现它设置了 x 和 y 值。

您的第三个示例给出了错误,因为

new
消息返回 Point 的实例,并且在 Point 的实例端没有实现
x:y:
消息。

考虑以下因素:

| pClass pInstance |
pClass := Point. "another reference to the class"
pInstance := pClass new. "calls a class-side method to create an instance"
pInstance setX: 5 setY: 6. "calls an instance-side method to set values"
pInstance

或者更简单地说,

| pInstance |
pInstance := Point x: 5 y: 6. "a class-side method returns an initialized instance"

请注意,当类端和实例端都存在相同的方法名称时,这会变得特别混乱。这在许多 OO 语言中是不允许的,因为每个类只有一个方法命名空间(并且类方法被指定为

static
)。然而,在 Smalltalk 中,由于类本身实际上是一流的对象,因此它们有自己的方法命名空间。一旦你掌握了它的窍门,它真的很有意义而且非常优雅。


0
投票

只是为了详细说明已经说过的内容。

a := Point initialize.
a class. 

如果您在最后一条语句上打印它,您将得到

-> Point class

b := Point x: 5 y: 3. 
b class

如果您在最后一条语句上打印它,您将得到

-> Point

区别在于,在第一种情况下,您将获得

Point class
的实例。该类用于生成
Point
的新实例。在第二种情况下,您将获得
Point
的实例。这才是你真正想要的东西。

最后,如果您浏览 Point 类,您会发现没有消息 x:y:该消息仅存在于

Point
的实例端,一旦分配给实例,x 和 y 值就应该是不可变的。

这一点进一步强调了,有一条消息

setX:setY
,但它被归类为“私人”,再次告诉您不应该使用它。

© www.soinside.com 2019 - 2024. All rights reserved.