2009-12-26 21 views
7
>> a = 5 
=> 5 
>> b = "hello, world!" 
=> "hello, world!" 
>> b.dup 
=> "hello, world!" 
>> a.dup 
TypeError: can't dup Fixnum 
    from (irb):4:in `dup' 
    from (irb):4 

Capisco che Ruby eseguirà una copia ogni volta che assegni un numero intero a una nuova variabile, ma perché Numeric#dup genera un errore?Perché i numeri non supportano .dup?

Non romperebbe l'astrazione, dal momento che tutti gli oggetti dovrebbero rispondere correttamente a .dup?

Riscrivere il metodo dup risolverà il problema, per quanto posso dire:

>> class Numeric 
>> def dup() 
>>  self 
>> end 
>> end 

cosa questo ha un rovescio della medaglia non sto vedendo? Perché questo non è incorporato in Ruby?

risposta

14

La maggior parte degli oggetti in Ruby vengono passati per riferimento e possono essere dupperati. Ad esempio:

s = "Hello" 
t = s  # s & t reference to the same string 
t.upcase! # modifying either one will affect the other 
s # ==> "HELLO" 

alcuni oggetti in Ruby sono immediati, però. Vengono passati per valore, può esserci solo uno di questi valori e quindi non può essere duplicato. Si tratta di qualsiasi (piccolo) numero intero, true, false, simboli e nil. Molti float sono anche immediatamente disponibili in Ruby 2.0 su sistemi a 64 bit.

In questo esempio (assurdo), qualsiasi "42" manterrà la stessa variabile di istanza.

class Fixnum 
    attr_accessor :name 
    alias_method :original_to_s, :to_s 
    def to_s 
    name || original_to_s 
    end 
end 
42.name = "The Answer" 
puts *41..43 # => 41, The Answer, 43 

Dal momento che normalmente si aspetta something.dup.name = "new name" di non pregiudicare qualsiasi altro oggetto che la copia ottenuta con dup, Ruby sceglie di non definire dup su immediates.

La tua domanda è più complessa di quanto sembri. C'era some discussion su ruby-core su come questo può essere reso più facile. Inoltre, altri tipi di oggetti numerici (float, bignum, razionali e numeri complessi) non possono essere copiati, sebbene non siano nemmeno immediati.

noti che ActiveSupport (parte di rotaie) forniscono il metodo duplicable? su tutti gli oggetti

+1

ActiveSupport, not Rails, fornisce il metodo 'duplicable?'.Quindi puoi semplicemente installare ActiveSupport e richiederlo ('richiede 'active_support'') se vuoi che (e molti altri) metodi di utilità. – henrikhodne

+0

Infatti. Aggiornato. –

+0

Il link deve essere sostituito da https://bugs.ruby-lang.org/issues/1844. Inoltre, la funzione è stata rifiutata perché non sono stati fatti progressi, a quanto pare. –

2

Il problema con la funzione dup() che è stata definita è che non restituisce una copia dell'oggetto, ma restituisce l'oggetto stesso. Questo non è quello che dovrebbe fare una procedura duplicate.

Non lo so Ruby, ma un possibile motivo mi viene in mente per dup non essere definita per i numeri è che un numero è un tipo di base e, quindi, di fare qualcosa di simile:

>> a = 5 
>> b = a 

sarebbe automaticamente assegnare il valore 5 nella variabile b, anziché rendere b e a punto sullo stesso valore in memoria.

+0

Questo è esattamente ciò che fa Ruby, in modo che quando si utilizza il mio metodo con un tipo numerico, verrà restituito una nuova copia. (e per qualsiasi altro tipo, restituirà un riferimento all'originale) –

+0

Suppongo che sia vero. Dal punto di vista della funzionalità, quindi, probabilmente non c'è un problema con il tuo codice. Tuttavia, la ragione per cui Ruby non l'avrebbe incorporata è molto probabilmente perché sarebbe solo la duplicazione della funzionalità di assegnazione integrata dei tipi di base di Ruby. – cmptrgeekken

Problemi correlati