Asignación de objetos en Ruby [cerrado
-
27-10-2019 - |
Pregunta
Viniendo de un fondo C ++ tengo curiosidad por la asignación de objetos en Ruby. Qué consideraciones (si las hay) deben hacerse para las siguientes asignaciones de objetos:
class MyClass
attr_accessor :a, :b
def initialize(a, b)
@a = a
@b = b
end
def some_method
puts "#{self.a} #{self.b}"
end
end
m = MyClass.new("first", "last")
n = MyClass.new("pizza", "hello")
q = n
q.some_method
Solución
Si está familiarizado con C ++, es posible que desee considerar cada variable en Ruby, instancia o de otra manera, como referencia a otro objeto. Dado que todo en Ruby es un objeto, incluso nil
, que es de tipo nilclass, esto es cierto bajo todas las circunstancias.
Para determinar a qué objeto está haciendo referencia, puede usar el object_id
método para diferenciar. Eso es similar a la conversión a un puntero que usa &
En C ++.
Considera esto:
a = "foo"
b = a
a.object_id == b.object_id
# => true
Ya que a
es una referencia a esa cadena, y b
es una copia de a
, entonces son en realidad diferentes referencias al mismo objeto.
Esto es importante porque las operaciones que modifican un objeto afectan todas las referencias a eso por igual:
a << "bar"
# => "foobar"
b
# => "foobar"
Sin embargo, operaciones que crean un nuevo El objeto no modificará todas las copias:
a += "baz"
# => "foobarbaz"
b
# => "foobar"
Muchos métodos en Ruby son identificados por un !
Para distinguir las versiones en el lugar versus las nuevas copias, pero este no siempre es el caso, por lo que debe estar familiarizado con cada método para estar seguro.
Generalmente una tarea reemplazará una referencia antigua con una nueva, por lo que, como regla general, el pulgar, =
Reemplazará las viejas referencias. Esto aplica a +=
, -=
, ||=
, &&=
y así.
Editar: Actualizado basado en el comentario de Phrogz sobre el uso ObjectSpace._id2ref(object_id)
para convertir un identificador de objeto en un objeto.
Otros consejos
Como todo es un objeto en Ruby, la asignación siempre es por referencia.
Entonces, tomando su clase como entrada, la siguiente será la salida para varias operaciones:
str = "foo"
foo = MyClass.new(str, "bar")
foo.some_method # foo bar
bar = foo
bar == foo # true
bar.some_method # foo bar
str << "bar" # strings are mutable on ruby, so str is now "foobar"
foo.some_method # foobar bar
bar.some_method # foobar bar
Reescribiría esto como:
class MyClass
attr_accessor :a, :b
def initialize(a, b)
self.a = a
self.b = b
end
def some_method
puts "#{a} #{b}"
end
end
De esta manera, realmente está utilizando los métodos getter/setter definidos por attr_accessor
Dentro de tu clase
Cuando asignas q = n
, Q solo hace referencia a la misma ubicación de memoria que se estableció para n. El objeto no se copia.