Smalltalk 为什么可以';在从Dictionary类派生的类中重写#at:put:方法?

Smalltalk 为什么可以';在从Dictionary类派生的类中重写#at:put:方法?,smalltalk,Smalltalk,我试图在Smalltalk中实现一个特定的Dictionary类,它需要覆盖Pharo和Squeak中的#at:put:方法。但是,当我创建一个类,将#at:put:作为实例方法并发送该方法时,我得到了错误: Error: Instances of '#SortedDictionary' class are not indexable 类别定义如下: Dictionary subclass: #SortedDictionary instanceVariableNames: 'index'

我试图在Smalltalk中实现一个特定的Dictionary类,它需要覆盖Pharo和Squeak中的#at:put:方法。但是,当我创建一个类,将
#at:put:
作为实例方法并发送该方法时,我得到了错误:

Error: Instances of '#SortedDictionary' class are not indexable
类别定义如下:

Dictionary subclass: #SortedDictionary
   instanceVariableNames: 'index'
   classVariableNames: ''
   category: 'MyApplication'
通过覆盖新实例创建实例:

!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
    super new.
    ^self initialize! !
实例初始化为:

initialize
  index := Heap new.
  ^self
实例方法定义为:

at: anIndex put: aValue
  index add: anIndex.
  ^self at: anIndex put: aValue! !
我在工作区中使用脚本进行测试:

| d |
d := SortedDictionary new.
d at: 1 put: 3.
我试图创建一个不是从
#Dictionary
派生的类,而是从
#Object
派生的类,并使用了一个实例变量
dict
,其中包含
#Dictionary
的实例,但结果相同

为什么我不能覆盖
#at:put:
以及如何覆盖此方法

编辑 多亏了@Lougler和@aka.nice,我本应该做以下工作:

!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
    ^super new initialize! !
做这种错事完全是愚蠢的!在最初的错误代码中,我试图索引一个nil对象

以及:

嗯,在解决新的问题之前,我从来没有来解决过这个问题


再次感谢大家不辞辛劳地帮忙

通常,集合实例(更准确地说是集合的子类)是使用#new:,而不是#new创建的

传递给new:的参数是一个大小,可以是固定大小集合的大小(如
Array new:3
),也可以是可变大小集合的一些预先分配的大小(如
OrderedCollection
Set
Dictionary
,…)

从邮票上看,我想你是在一个吱吱声或法老味,所以我将继续解释这些方言,它可能会略有不同的其他口味

在Squeak/Pharo中,请参见HashedCollection类的定义>>新建:

new: nElements
    "Create a Set large enough to hold nElements without growing"
    ^ self basicNew initialize: (self sizeFor: nElements)
它发送initialize:notinitialize。 因此,您必须做的第一件事是在类的实例端定义initialize:第二件事是删除new/new:的定义:在Squeak/Pharo中很少需要重写它们

目前,当您告诉
自我初始化
自我到底是什么时,您的#新定义有一个问题?它是类
SortedDictionary
,因此您要初始化类,而不是实例!你回答的是类,而不是新创建的实例,所以你稍后会发送:put:给类

它应该是类似于
newInstance:=supernew的东西^新实例初始化


最后,您的at:put:定义将永远循环,它应该调用
super at:。。。放:…

几根刺来挑。

当您以文本形式编写Smalltalk代码时,就像我们在这里所做的那样,
您可以使用格式
{classname|blank} {class|blank} >> methodHead {classname | blank}{classname | blank}>>方法头 其中第一个字段命名类,第二个字段告知它是类端还是实例端,“>>”表示源代码的开始。 如果您不命名该类,我们将假定该类与上次命名的类相同。 如果您不说它是类端,我们假设它是实例端。 因此,您的方法将写为

SortedDictionary class>>new ^super new initialize >>initialize index := Heap new >>at: anIndex put: aValue index add: anIndex. ^super at: anIndex put: aValue SortedDictionary类>>新建 ^超新 初始化 >>初始化 索引:=新堆 >>at:an指数put:aValue 索引添加:一个索引。 ^超级at:anIndex put:aValue 其次,因为您正在定义一个子类,所以只需要定义 如果必须重写从超类继承的方法,则可以使用自己的#new(和/或#new:)方法
(但你知道这一点)

第三,无论何时编写#initialize方法,都希望养成将“super initialize”作为第一行的习惯

一旦你养成了上述习惯,你就会想摆脱以“^super new initialize”开头编写新方法的习惯,转而养成以“self basicNew initialize”开头的习惯

我知道,每个人都学会用另一种方式去做。(叹气)
但这是大错特错。

如果你能弄明白为什么会这样,那就多加一分。;-)

@潜伏者:正如我在引言中所写,我得到了错误:“错误:#SortedDictionary类的实例是可注释索引的”。在调试器中,smalltalk解释器似乎更喜欢使用原语而不是我的重写方法。很抱歉,我错过了。您是否为
SortedDictionary
类定义了
新的
运算符?我在你的问题陈述中没有看到,你是对的。我刚刚编辑了问题正文,添加了
new
类方法的定义。我相信
at:put:
选择器定义中的
self-at:anIndex-put:aValue
是循环引用,但不是错误消息的原因。您的
新方法看起来不正确。身体应该是
^super new initialize
@lowerer:你有两个账户是对的!谢谢我根据你的建议编辑了这个问题。谢谢是的,这是正确的答案。谢谢虽然在这个特定的实例中,我并不太关心(到目前为止)限制元素数量的
#new:
方法。 SortedDictionary class>>new ^super new initialize >>initialize index := Heap new >>at: anIndex put: aValue index add: anIndex. ^super at: anIndex put: aValue