2012-08-14 8 views
9

Ho una classe Pointer con un singolo attributo :contents, che punta a un oggetto della classe MyObject.Quale metodo definire su una classe Ruby per fornire dup/clone per le sue istanze?

class MyObject 
    def hello; "hello" end 
end 

class Pointer 
    attr_reader :contents 
    def initialize(cont); @contents = cont end 
    # perhaps define some more state 
end 

voglio che il mio Pointer per essere in grado di fare copie di se stesso. So che il metodo #dup è definito per impostazione predefinita, mentre il metodo #clone deve essere sostituito per poter eseguire copie approfondite. Ma qui, le copie non devono essere troppo profonde. Quindi, il primo dilemma che ho è, dovrei scavalcare il metodo #dup, perché in realtà non voglio copiare lo stato aggiuntivo del mio Pointer, basta crearne uno nuovo che punta alla stessa istanza MyObject? O dovrei astenermi da overridine #dup, perché non sono "supposto" ed eseguire l'override di #clone con un metodo che esegue copie poco profonde?

Gradirei commenti su quanto sopra, ma supponiamo che sceglierò di sovrascrivere #dup. Ho potuto fare proprio questo:

class Pointer 
    def dup; self.class.new(contents) end 
end 

Ma in linea, ho letto qualcosa come "il DUP metodo di chiamerà il inizializzare copiare metodo". Inoltre, this guy scrive su #initialize_clone, #initialize_dup e #initialize_copy in Ruby. Questo mi lascia domandare, è forse la miglior pratica come questa?

class Pointer 
    def initialize_copy 
    # do I don't know what 
    end 
end 

O come questo?

class Pointer 
    def initialize_dup 
    # do I don't know what 
    end 
end 

O devo solo dimenticare sproloqui online Scritto per confondere i principianti e andare per superiori #dup senza preoccupazioni?

Inoltre, capisco che posso solo chiamare #dup senza definire alcuna consuetudine #dup, ma cosa se voglio definire #dup con un comportamento diverso?

Inoltre, la stessa domanda si applica a #clone - devo provare a definire #initialize_clone o solo #clone?

+0

Posso chiedere perché stai facendo una classe puntatore a tutti ? Le variabili di Ruby sono già tutti riferimenti/puntatori. –

+0

A volte si desidera implementare la propria struttura dati o si desidera che il puntatore esegua trucchi. L'argomento della domanda non è se la classe è un puntatore o qualcos'altro, ma se devi sapere, sono interessato alle strutture Zz di Ted Nelson, e Ted definisce quelli che lui chiama "cursori", così ho deciso di chiamarli "punti" "come in Emacs. Sai, devi implementare la classe pointer quando le specifiche della struttura dati lo richiedono. –

risposta

16

Dalla mia esperienza, l'overloading di #initialize_copy funziona bene (mai sentito parlare di initialize_dup e initialize_clone).

L'initialize_copy originale (che inizializza ogni variabile di istanza con i valori l'oggetto originale) è disponibile attraverso super, così io di solito fare:

class MyClass 
    def initialize_copy(orig) 
    super 
    # Do custom initialization for self 
    end 
end 
+0

Come si confronta con la ridefinizione di #dup? È mai o.k. ridefinire #dup? –

+3

La grande differenza è che, ridefinendo #dup, 'self' è l'oggetto originale.Pertanto non hai accesso allo stato interno del nuovo oggetto. È il contrario in #initialize_copy –

+2

Un'altra differenza: ho appreso nel modo più duro che, nell'implementazione di Ruby di Matz, alcune funzioni C chiamano per es. rb_obj_dup direttamente invece di usare il normale metodo di invio. #dup potrebbe essere uno di questi. Il che significa che alcune cose di libreria standard * non * chiamerebbero la tua versione di #dup mentre * chiamerebbero * #initialize_copy –