为什么我不能覆盖从 Dictionary-class 派生的 class 中的 #at:put: 方法?
Why can't I override the #at:put: method in a class derived from the Dictionary-class?
我尝试在 Smalltalk 中实现一个特定的字典 class,它需要覆盖 Pharo 和 Squeak 中的#at:put: 方法。但是,当我创建一个具有 #at:put:
的 class 作为实例方法并发送该方法时,出现错误:
Error: Instances of '#SortedDictionary' class are not indexable
class定义如下:
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.
我试图创建一个 class 不是 派生自 #Dictionary
但来自 #Object
并使用实例变量 dict
包含 #Dictionary
的实例,但结果相同。
为什么我不能覆盖 #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
问题之前,我从来没有来解决这个问题。
再次感谢大家不厌其烦的帮忙!
通常,集合的实例(更准确地说是集合的子class)是使用#new: 而不是#new 创建的。
传递给 new: 的参数是一个大小,可以是固定大小集合的大小(如 Array new: 3
),也可以是可变大小集合的一些预分配大小(如 OrderedCollection
, Set
, Dictionary
, ...).
从图章来看,我猜你是 Squeak 或 Pharo 口味的,所以我将继续用这些方言解释,其他口味可能略有不同。
在Squeak/Pharo中,见HashedCollection的定义class>>new:
new: nElements
"Create a Set large enough to hold nElements without growing"
^ self basicNew initialize: (self sizeFor: nElements)
它发送初始化:不初始化。
所以你要做的第一件事是定义初始化:在你的 class 的实例端,第二件事是删除 new/new 的定义:在 [=35= 中很少需要覆盖这些].
目前您的#new 定义有问题,当您告诉 self initialize
self 到底是什么时?它是 class SortedDictionary
,所以你初始化 class,而不是实例!你回答 class,而不是新创建的实例,所以你稍后发送 at:put: 到 class...
应该是 newInstance := super new. ^newInstance initialize
。
最后,您的 at:put: 定义将永远循环,它应该调用 super at: ... put: ...
几尼特可供选择。
当您将 Smalltalk 代码编写为文本时,就像我们在这里所做的那样,
你可以使用格式
{classname|blank} {class|blank} >> methodHead
其中第一个字段命名为 class,第二个字段表示它是 class 端还是实例端,'>>' 表示源代码的开始。
如果您不命名 class,我们假设与最后一个命名的 class 相同。
如果你不说是class端,我们就认为是实例端。
所以你的方法会写成
SortedDictionary class>>new
^super new
initialize
>>initialize
index := Heap new
>>at: anIndex put: aValue
index add: anIndex.
^super at: anIndex put: aValue
其次,由于您正在定义一个子class,您只需要定义
你自己的#new (and/or #new:) 方法,如果你必须覆盖从 superclasses 继承的方法。
(但你知道的)。
第三,每当你写一个#initialize方法时,你要养成在第一行写'super initialize.'的习惯。
一旦你养成了上述习惯,你就会想摆脱以“^super new initialize”开头编写#new 方法的习惯,养成以 [=35 开头的习惯=] 代替。
我知道,每个人 都学会了以其他方式做到这一点。 (叹气。)
但那是错误的。
如果您能弄清楚为什么会这样,请加分。 ;-)
我尝试在 Smalltalk 中实现一个特定的字典 class,它需要覆盖 Pharo 和 Squeak 中的#at:put: 方法。但是,当我创建一个具有 #at:put:
的 class 作为实例方法并发送该方法时,出现错误:
Error: Instances of '#SortedDictionary' class are not indexable
class定义如下:
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.
我试图创建一个 class 不是 派生自 #Dictionary
但来自 #Object
并使用实例变量 dict
包含 #Dictionary
的实例,但结果相同。
为什么我不能覆盖 #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
问题之前,我从来没有来解决这个问题。
再次感谢大家不厌其烦的帮忙!
通常,集合的实例(更准确地说是集合的子class)是使用#new: 而不是#new 创建的。
传递给 new: 的参数是一个大小,可以是固定大小集合的大小(如 Array new: 3
),也可以是可变大小集合的一些预分配大小(如 OrderedCollection
, Set
, Dictionary
, ...).
从图章来看,我猜你是 Squeak 或 Pharo 口味的,所以我将继续用这些方言解释,其他口味可能略有不同。
在Squeak/Pharo中,见HashedCollection的定义class>>new:
new: nElements
"Create a Set large enough to hold nElements without growing"
^ self basicNew initialize: (self sizeFor: nElements)
它发送初始化:不初始化。 所以你要做的第一件事是定义初始化:在你的 class 的实例端,第二件事是删除 new/new 的定义:在 [=35= 中很少需要覆盖这些].
目前您的#new 定义有问题,当您告诉 self initialize
self 到底是什么时?它是 class SortedDictionary
,所以你初始化 class,而不是实例!你回答 class,而不是新创建的实例,所以你稍后发送 at:put: 到 class...
应该是 newInstance := super new. ^newInstance initialize
。
最后,您的 at:put: 定义将永远循环,它应该调用 super at: ... put: ...
几尼特可供选择。
当您将 Smalltalk 代码编写为文本时,就像我们在这里所做的那样,
你可以使用格式
{classname|blank} {class|blank} >> methodHead其中第一个字段命名为 class,第二个字段表示它是 class 端还是实例端,'>>' 表示源代码的开始。 如果您不命名 class,我们假设与最后一个命名的 class 相同。 如果你不说是class端,我们就认为是实例端。 所以你的方法会写成
SortedDictionary class>>new ^super new initialize >>initialize index := Heap new >>at: anIndex put: aValue index add: anIndex. ^super at: anIndex put: aValue
其次,由于您正在定义一个子class,您只需要定义
你自己的#new (and/or #new:) 方法,如果你必须覆盖从 superclasses 继承的方法。
(但你知道的)。
第三,每当你写一个#initialize方法时,你要养成在第一行写'super initialize.'的习惯。
一旦你养成了上述习惯,你就会想摆脱以“^super new initialize”开头编写#new 方法的习惯,养成以 [=35 开头的习惯=] 代替。
我知道,每个人 都学会了以其他方式做到这一点。 (叹气。)
但那是错误的。
如果您能弄清楚为什么会这样,请加分。 ;-)