簡體   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