Domanda
Mi aspettavo che il seguente codice stampasse "8", "111" e "999". Supponevo che ciascuno a, b, c e d punta alla stessa posizione di memoria. Se cambio la posizione attraverso una di esse, perché l'altra non dovrebbe cambiare? Chiaramente, la mia logica è scarsa o ho trascurato qualcosa. Stampa "7", "7" e "8", invece.
Perché?
a=b=c=d=7
b = 8
puts d
c = 111
puts a
d = 999
puts b
[Chiarimento]
Il motivo della mia confusione è l'esempio nel il libro (pagina 20). Loro cambiano in modo simile i valori, ma ottengono i risultati che ho suggerito sopra. Stiamo parlando dello stesso problema?
Soluzione
a=b=c=d=7
# a, b, c and d points to the same integer object "7"
b = 8
# b now points to a new object "8"
# "=" does not change the value of the pointer integer,
# it assings a new reference like in the line above
puts d
# obviously, d still points to "7"
c = 111
# c now points to another integer object "111"
puts a
# a still points to "7"
d = 999
# d now points to a new integer object "999"
puts b
# b still points to "8"
in Ruby, l'oggetto Numero intero è immutabile, quindi non è possibile assegnare un numero intero a riferimento multiplo e modificarne il valore dopo.
Come suggerito da @pts, dovresti usare un array per racchiudere il tuo riferimento intero perché gli array sono mutabili e puoi cambiare il valore dopo.
a=b=c=d=[7]
b[0] = 8
puts d[0]
c[0] = 111
puts a[0]
d[0] = 999
puts b[0]
PRECISAZIONE:
Se provieni da uno sfondo C ++, potrebbe essere strano perché C ++ fa 2 cose con la stessa sintassi, assegnando il riferimento e modificando il valore a cui si fa riferimento.
int a = 10; // creates an int on the stack with value 10
int& b = a; // creates a reference to an int and references the a variable
b = 5; // change the value referenced by b (so a) to 5
// a and b now hold the value 5
In Ruby, i riferimenti sono mutabili e gli interi no (esattamente il contrario di C ++). Quindi l'assegnazione di un riferimento cambierà effettivamente il riferimento e non il valore di riferimento.
Un'altra soluzione sarebbe quella di creare una classe che sia un intero mutabile:
class MutableInteger
attr_writer :value
def initialize(value)
@value = value
end
def inspect
value
end
def to_i
value
end
def to_s
value
end
end
a = b = MutableInteger.new(10)
a.value = 5
puts b
# prints 5
Altri suggerimenti
Il modo più semplice per ottenere l'output previsto è l'utilizzo di un array a elemento singolo:
a=b=c=d=[7]
b[0] = 8
puts d[0]
c[0] = 111
puts a[0]
d[0] = 999
puts b[0]
Per sapere se aeb si riferiscono allo stesso oggetto, usa a .__ id__ == b .__ id__
.
Non puntano alla stessa posizione di memoria. Ruby non passa per riferimento .
Dopo la prima riga, a, b, c e d puntano tutti allo stesso oggetto Fixnum (con valore 7). Tuttavia, quando si esegue b = 8, b ora punta a un nuovo oggetto Fixnum (con valore 8).
In effetti stai assegnando b a un nuovo oggetto, piuttosto che mutare l'oggetto esistente. Questo è il motivo per cui le modifiche non vengono propagate come previsto.
Se stai confrontando con C ++, è come assegnare un puntatore per valore, piuttosto che assegnare per riferimento.
Consiglio vivamente di leggere C passa per riferimento Java e Ruby no