我尝试在Smalltalk中实现一个特定的Dictionary类,它需要覆盖Pharo和Squeak中的#at:put:方法。但是当我创建一个具有#at:put:
作为实例方法的类并且我发送该方法时,我得到错误:
Error: Instances of '#SortedDictionary' class are not indexable
类定义如下:
Dictionary subclass: #SortedDictionary
instanceVariableNames: 'index'
classVariableNames: ''
category: 'MyApplication'
通过覆盖new来创建实例:
!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.
我尝试从<{1}}创建一个而不是的类,但是来自#Dictionary
,并使用包含#Object
实例的实例变量dict
,但结果相同。
为什么我无法覆盖#Dictionary
和以及如何覆盖此方法?
感谢@lurker和@ aka.nice我应该做到以下几点:
#at:put:
做错了是彻头彻尾的愚蠢!在原始和错误的代码中,我试图索引一个零对象。
和
!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
^super new initialize! !
好吧,在解决!SortedDictionary instance methodsFor: 'accessing' stamp: 'nanitous 9/28/2015 19:17'!
at: anIndex put: aValue
index add: anIndex.
^super at: anIndex put: aValue! !
问题之前,我从未解决过这个问题。
再次感谢大家帮忙解决问题!
答案 0 :(得分:4)
通常,使用#new:创建集合实例(更确切地说是Collection的子类),而不是#new。
传递给new的参数是一个大小,可以是固定大小集合的大小(如Array new: 3
),也可以是可变大小集合的预分配大小(如OrderedCollection
,{{ 1}},Set
,...)。
从邮票上看,我猜你的是Squeak或Pharo的味道,所以我将继续用这些方言解释,它可能会因其他口味而略有不同。
在Squeak / Pharo中,查看HashedCollection类的定义&gt;&gt; new:
Dictionary
它发送初始化:不初始化。 因此,您要做的第一件事就是定义初始化:在类的实例端,第二件事是删除new / new的定义:在Squeak / Pharo中很少需要覆盖它们。
目前,当你告诉new: nElements
"Create a Set large enough to hold nElements without growing"
^ self basicNew initialize: (self sizeFor: nElements)
什么是自我时,你的#new定义存在问题?它是类self initialize
,所以你初始化类,而不是实例!你回答这个类,而不是新创建的实例,所以你以后发送:put:to class ...
应该是SortedDictionary
。
最后,你的at:put:定义将永远循环,它应该调用newInstance := super new. ^newInstance initialize
答案 1 :(得分:0)
要挑选几个尼特。
当你将Smalltalk代码写为文本时,例如我们在这里做的,
你可以使用格式
{classname|blank} {class|blank} >> methodHead第一个字段命名该类,第二个字段告诉它是类侧还是实例侧,'&gt;&gt;'表示源代码的开始。 如果您没有为该类命名,我们假设与最后一个命名的类相同。 如果你不说它是类侧,我们假设它是实例方面。 因此,您的方法将写为
SortedDictionary class>>new ^super new initialize >>initialize index := Heap new >>at: anIndex put: aValue index add: anIndex. ^super at: anIndex put: aValue
其次,既然你要定义一个子类,你只需要定义
如果必须覆盖从超类继承的那个方法,那么你自己的#new(和/或#new :)方法。
(但你知道)。
第三,每当你编写#initialize方法时,你都想养成写'超级初始化'的习惯。作为第一行。
一旦你养成这种习惯,你就会想要摆脱以'^ super new initialize'开头写#new方法的习惯,养成用'self basicNew initialize'开始它们的习惯代替。
我知道,每个人都学会以其他方式去做。 (叹气。)
但那太糟糕了
如果你能弄清楚为什么会这样,那就加分吧。 ;-)