为什么我不能覆盖从Dictionary-class派生的类中的#at:put:方法?

时间:2015-09-28 17:45:02

标签: smalltalk

我尝试在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! ! 问题之前,我从未解决过这个问题。

再次感谢大家帮忙解决问题!

2 个答案:

答案 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'开始它们的习惯代替。

我知道,每个人都学会以其他方式去做。 (叹气。)
但那太糟糕了 如果你能弄清楚为什么会这样,那就加分吧。 ;-)