Question
Je m'attendais à ce que le code suivant indique "8", "111" et "999". J'ai supposé que chacun a, b, c et d pointe vers le même emplacement de mémoire. Si je change de lieu par l’un d’eux, pourquoi l’autre ne changerait-il pas? Clairement, ma logique est mauvaise ou j'ai oublié quelque chose. Il imprime "7", "7". et "8", à la place.
Pourquoi?
a=b=c=d=7
b = 8
puts d
c = 111
puts a
d = 999
puts b
[Précision]
La cause de ma confusion est l’exemple de du livre (page 20). Ils y changent les valeurs de la même manière, mais ils obtiennent les résultats que j'ai suggérés ci-dessus. Parlons-nous du même problème?
La solution
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"
dans Ruby, l’objet Integer étant immuable, vous ne pouvez pas attribuer un Integer à plusieurs références et modifier sa valeur après.
Comme @pts l'a suggéré, vous devriez utiliser un tableau pour envelopper votre référence Integer car les tableaux sont mutables, vous pouvez changer la valeur après.
a=b=c=d=[7]
b[0] = 8
puts d[0]
c[0] = 111
puts a[0]
d[0] = 999
puts b[0]
CLARIFICATION:
Si vous venez d'un arrière-plan C ++, cela peut paraître étrange car C ++ fait 2 choses avec la même syntaxe, attribuant la référence et modifiant la valeur référencée.
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
En Ruby, les références sont modifiables et les entiers ne le sont pas (exactement le contraire de C ++). Donc, assigner une référence changera réellement la référence et non la valeur référencée.
Une autre solution serait de créer une classe qui est un entier mutable:
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
Autres conseils
Le moyen le plus simple d'obtenir le résultat attendu consiste à utiliser un tableau à un seul élément:
a=b=c=d=[7]
b[0] = 8
puts d[0]
c[0] = 111
puts a[0]
d[0] = 999
puts b[0]
Pour obtenir si a et b font référence au même objet, utilisez a .__ id__ == b .__ id __
.
Ils ne pointent pas vers le même emplacement mémoire. Ruby ne passe pas par référence .
Après la première ligne, a, b, c et d pointent tous vers le même objet Fixnum (avec la valeur 7). Cependant, lorsque vous exécutez b = 8, b pointe maintenant vers un nouvel objet Fixnum (avec la valeur 8).
Effectivement, vous attribuez b à un nouvel objet, plutôt que de muter l'objet existant. C’est la raison pour laquelle vos modifications ne sont pas propagées comme prévu.
Si vous comparez avec C ++, cela revient à assigner un pointeur par valeur plutôt qu’à attribuer par référence.
Je recommande fortement de lire C passe par référence Java et Ruby ne le font pas