2013-07-28 9 views
10

Sto lavorando a una soluzione per i disegni tecnici (svg/ruby). Voglio manipolare rettangoli, e hanno un metodo di add! in questa classe:Perché non c'è un metodo di copia profonda in Ruby?

class Rect 
    def add!(delta) 
    @x1+=delta 
    ... # and so on 
    self 
    end 
end 

ho anche bisogno di un metodo che restituisce un addRect, ma non la manipolazione self:

def add(delta) 
    r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here 
    r.add! delta 
end 

dup e clone no fare la mia cosa ma:

def copy; Marshal.load(Marshal.dump(self)); end 

fa.

Perché una tale funzionalità di base non esiste in semplice Ruby? Per favore, non dirmi che potrei annullare add e add!, lasciando che il lavoro sia add e add! chiamandolo.

+7

Perché non esiste? Funziona: 'Marshal.dump' +' Marshal.load'. Puoi nominare alcuni dei linguaggi di programmazione che hanno una copia profonda a livello di lingua? –

+0

il tuo punto, penso, che io sono come un bambino viziato con Ruby, trovando tutto qui, che ho perso in altri posti MrGreen – halfbit

+0

"Perché" rende questa domanda difficile/impossibile per chiunque tranne Matz, et al., rispondere. –

risposta

5

Non sono sicuro del motivo per cui non esiste un metodo di copia profonda in Ruby, ma cercherò di formulare un'ipotesi basata sulle informazioni che sono riuscito a trovare (vedere link e citazioni sotto la riga).

A giudicare da queste informazioni, posso solo dedurre che il motivo per cui Ruby non ha un metodo di copia profonda è perché è molto raramente necessario e, nei pochi casi in cui è veramente necessario, ci sono altri modi relativamente semplici per eseguire lo stesso compito:

Come già sapete, l'utilizzo di Marshal.dump e Marshal.load è attualmente il metodo consigliato per eseguire questa operazione. Questo è anche l'approccio raccomandato da Programming Ruby (vedere gli estratti di seguito).

In alternativa, sono disponibili almeno 3 implementazioni disponibili in queste gemme: deep_cloneable, deep_clone e ruby_deep_clone; il primo è il più popolare.


Informazioni correlate

Ecco a discussion over at comp.lang.ruby che potrebbero far luce su questo. C'è another answer here con alcune discussioni associate, ma tutto torna a utilizzare Marshal.

Non ci sono state menzioni di copia profonda in Programming Ruby, ma c'erano alcune citazioni in The Ruby Programming Language. Ecco alcuni stralci relativi:

[...]

Un altro uso per Marshal.dump e Marshal.load è quello di creare copie profonde di oggetti:

def deepcopy(o) 
    Marshal.load(Marshal.dump(o)) 
end 

[...]

... il formato binario utilizzato da Marshal.dump e Marshal.load è in base alla versione e versioni più recenti o f Ruby non è garantito per essere in grado di leggere oggetti di marshalling scritti da versioni precedenti di Ruby.

[...]

Si noti che i file e flussi di I/O, così come metodo e vincolante oggetti, sono troppo dinamiche siano radunate; non ci sarebbe alcun modo affidabile per ripristinare il loro stato.

[...]

Invece di fare una copia completa difensivo della matrice, basta chiamare to_enum su di esso, e passare l'enumeratore risulta invece dell'array stessa. In effetti, stai creando un oggetto enumerable ma immutable per il tuo array.

+2

questo è più di una risposta; la mia conclusione - prendendo in considerazione i tuoi collegamenti - è che la copia (profonda) di un oggetto è (più o meno spesso) un puntatore per un cattivo design. – halfbit

+0

Riguardo l'ultimo punto riguardante l'utilizzo di to_enum. Ho provato questo, ma non funziona come previsto. Sto usando Ruby 2.2.0 a = [1,2,3,4] => [1, 2, 3, 4] b = a.to_enum => # a << 5 => [1, 2, 3, 4, 5] b => # Come sta creando enumerable crea un oggetto poxy immutabile per l'array? – RubyMiner

0

Perché non si può usare qualcosa di simile:

new_item = Item.new(old_item.attributes) 
new_item.save! 

Ciò copiare tutti gli attributi di elemento esistente in uno nuovo, senza problemi. Se hai altri oggetti, puoi semplicemente copiarli individualmente.

Penso che sia il modo più rapido per copiare un oggetto

+0

Se si ha a che fare con oggetti di tipo ActiveRecord, questo potrebbe funzionare, forse. Ma ovviamente non funzionerebbe con nessun oggetto Ruby. – flajann