繁体   English   中英

为什么不能在从Dictionary-class派生的类中重写#at:put:方法?

[英]Why can't I override the #at:put: method in a class derived from the Dictionary-class?

我尝试在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.

我试图使一个不是#Dictionary派生而是从#Object派生的类,并使用包含#Dictionary实例的实例变量dict ,但结果相同。

为什么我不能覆盖#at:put: 我怎么可以重写此方法?

编辑

感谢@lurker和@ aka.nice,我应该执行以下操作:

!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
    ^super new initialize! !

这样做是完全愚蠢的! 在原始错误的代码中,我试图索引一个nil对象。

和:

!SortedDictionary instance methodsFor: 'accessing' stamp: 'nanitous 9/28/2015 19:17'!
at: anIndex put: aValue
  index add: anIndex.
  ^super at: anIndex put: aValue! !

好吧,在解决#new问题之前,我从#new过解决这个问题。

再次感谢大家在此提供的帮助!

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

传递给new:的参数是一个大小,可以是固定大小集合的大小(例如Array new: 3 ),也可以是可变大小集合的一些预分配大小(例如OrderedCollectionSetDictionary等)。

从印章上看,我想您是使用Squeak或Pharo口味的,所以我将继续对这些方言进行解释,其他口味可能会略有不同。

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

new: nElements
    "Create a Set large enough to hold nElements without growing"
    ^ self basicNew initialize: (self sizeFor: nElements)

它发送初始化:不初始化。 因此,您要做的第一件事是在类的实例端定义initialize,第二件事是删除new / new的定义:在Squeak / Pharo中很少需要重写它们。

当前,当您告诉self initialize什么是self时,您在#new定义中存在问题。 它是SortedDictionary类,因此您可以初始化类,而不是实例! 然后您回答该类,而不是新创建的实例,因此稍后将at:put:发送到该类...

它应该像newInstance := super new. ^newInstance initialize newInstance := super new. ^newInstance initialize

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

几个尼特来挑选。

当您以文本形式编写Smalltalk代码时(例如我们在此处所做的操作),
您可以使用格式

{classname|blank} {class|blank} >> methodHead
第一个字段为类命名,第二个字段告诉它是类端还是实例端,“ >>”表示源代码的开始。 如果您不给班级命名,我们假定与上一个班级命名相同。 如果您不说它是类方面的,那么我们假定它是实例方面的。 所以你的方法将写成

\n\n     分类词典分类>>新\n         ^超级新\n             初始化\n\n     >>初始化\n         索引:=堆新\n\n     >> at:anIndex放置:aValue\n         索引添加:anIndex。\n         ^ super at:anIndex put:aValue\n\n

其次,由于要定义子类,因此如果必须重写从超类继承的方法,则只需定义自己的#new(和/或#new :)方法。
(但是你知道的)。

第三,每当编写#initialize方法时,您都想养成编写“超级初始化”的习惯。 作为其第一行。

并且一旦养成了习惯,就将不再习惯以'^ super new initialize'开头的#new方法的习惯,而是以'self basicNew initialize'开头的习惯。

我知道, 每个人都学会以其他方式做到这一点。 (叹。)
但这太不对了。
如果您能弄清楚为什么会这样的话,加分。 ;-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM