4

当谈到 Squeak Smalltalk 时,我有点新手,所以我可能会做错什么,或者对 Squeak 应该如何工作做出错误的假设。不过,我想知道我哪里出错了......

我试图让 Blower 类派生自 Array。Blower 基本上是一个数组,但有一个称为 index 的附加实例变量和一些方法。我认为当我创建一个新对象时初始化方法会自动运行,并且它会初始化数组和索引变量,但这似乎没有发生。如果我稍后“手动”运行初始化,它会按预期工作。

Array variableSubclass: #Blower
instanceVariableNames: 'index'
(...)

Blower >> initialize
super initialize.
1 to: self size do: [ :ix | self at: ix put: ix ].
self shuffle.
index := 1.

如果我在工作区中执行以下操作: blower := Blower new: 10. blower inspect.

检查窗口显示(不是我所期望的): \#( nil nil nil nil nil nil nil nil nil nil ) index: nil

如果我手动运行初始化,检查窗口是正确的:

blower initialize.

\#( 6 4 1 10 2 8 3 ... )
index: nil

那么当我创建 Blower 并正确设置它时,为什么不初始化运行呢?反正有没有自动化这个,所以它发生在创建?IE。初始化工作?

4

2 回答 2

5

看看方法 ArrayedCollection class >> new。它覆盖 new 以调用 new: 以 0 作为参数。这替换了调用初始化的 Behavior 中 new 的默认实现。如果你真的想这样做,在你的类中实现 new 和 new: 作为类方法。在每种情况下,调用 super 然后调用 initialize。

new
   ^super new initialize

new: sizeRequested
   ^(super new: sizeRequested) initialize

说了这么多,从 Array 子类化是一个非常糟糕的主意。问问自己“在我目前使用阵列的任何地方使用鼓风机是否合理?”。如果不是,它不是一个好的子类。任何时候你从一个集合类子类化你几乎总是做错了。你想要的是一个名为 Blower 的类,它是 Object 的一个子类,包含两个实例变量——一个用于数组,一个用于索引。您的类现在将正常初始化。对于要发送到数组的任何操作,请在 Blower 中编写一个方法以将其委托给实例变量。

于 2013-10-14T14:24:26.277 回答
1

David Buck 说的是正确的,但还有一些内容要补充,具体到 Squeak:

  1. 一些集合在实例创建时调用 #initialize: 而不是 #initialize(参见例如 HashedCollection)

  2. 其他一些可以同时发送 #initialize 然后 #initialize:(参见 SharedQueue)

  3. 但是Array class>>new: 有一个完全绕过initialize的具体实现(为了速度,要知道初始化一个Array不需要什么)

正如大卫所说,将 Array 子类化通常是一个坏主意,而且看看 Squeak,已经有太多的反例了。

于 2013-10-27T21:04:25.707 回答