Smalltalk 为什么可以';在从Dictionary类派生的类中重写#at:put:方法?
我试图在Smalltalk中实现一个特定的Dictionary类,它需要覆盖Pharo和Squeak中的#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'
#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