>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5
cómo puedo configurar 'b' para que realmente sea 'a', de modo que en el ejemplo, la variable a se convertirá en cuatro también. Gracias.ruby variable como el mismo objeto (¿punteros?)
>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5
cómo puedo configurar 'b' para que realmente sea 'a', de modo que en el ejemplo, la variable a se convertirá en cuatro también. Gracias.ruby variable como el mismo objeto (¿punteros?)
class Ref
def initialize val
@val = val
end
attr_accessor :val
def to_s
@val.to_s
end
end
a = Ref.new(4)
b = a
puts a #=> 4
puts b #=> 4
a.val = 5
puts a #=> 5
puts b #=> 5
Al hacer b = a
, b
puntos para el mismo objeto que a
(tienen el mismo object_id
) .
Al hacer a = some_other_thing
, a apuntará a otro objeto, mientras que b
se mantendrá sin cambios.
Para Fixnum
, nil
, true
y false
, no se puede cambiar el valor sin cambiar el object_id
. Sin embargo, puede cambiar otros objetos (cadenas, arrays, hashes, etc.) sin cambiar object_id
, ya que no utiliza la asignación (=
).
Ejemplo con cuerdas:
a = 'abcd'
b = a
puts a #=> abcd
puts b #=> abcd
a.upcase! # changing a
puts a #=> ABCD
puts b #=> ABCD
a = a.downcase # assigning a
puts a #=> abcd
puts b #=> ABCD
Ejemplo con matrices:
a = [1]
b = a
p a #=> [1]
p b #=> [1]
a << 2 # changing a
p a #=> [1, 2]
p b #=> [1, 2]
a += [3] # assigning a
p a #=> [1, 2, 3]
p b #=> [1, 2]
No se puede. Las variables contienen referencias a valores, no referencias a otras variables.
Esto es lo que el código de ejemplo está haciendo:
a = 5 # Assign the value 5 to the variable named "a".
b = a # Assign the value in the variable "a" (5) to the variable "b".
b = 4 # Assign the value 4 to the variable named "b".
a # Retrieve the value stored in the variable named "a" (5).
Consulte este artículo para una discusión más a fondo de este tema: pass by reference or pass by value.
¿No hay forma de hacer esto? ¿En absoluto? Incluso con algo de kludge? ¿Ningún valor que pueda representar la referencia? He descubierto que puedo hacer todo tipo de cosas locas en ruby con bastante facilidad, me sorprende que esto no sea posible. Gracias por su respuesta. Quiero básicamente ocultar la variable real, ¿podría adaptar el método set de la variable para establecer también la otra variable? ¿Esto incurriría en gastos generales? – Orbit
No, no usa la sintaxis en su ejemplo. Podría hacer algunos trucos de fantasía con 'eval' para escribir funciones que cargan/almacenan los valores en otras variables, pero eso es todo. Ver esto [discusión de paso de Ruby por referencia vs valor] (http://www.ruby-forum.com/topic/41160). – maerics
¡Esto está mal! b = a más enfáticamente NO asigna 5 a b porque 5 es el valor en a. El valor en a es una referencia a un fixnum. b = a asigna esa referencia a b. –
No soy un experto Ruby. Pero para un Kluge técnicamente loco ... que sólo funcionaría si se sentía como ir a través eval
cada vez que trabajó con una variable:
>> a = 5
=> 5
>> b = :a
=> :a
>> eval "#{b} = 4"
=> 4
>> eval "#{a}"
=> 4
>> eval "#{b}"
=> 4
Tenga en cuenta que un uso directo de b
todavía le dará :a
y usted puede 't utilizar en expresiones que no están en eval
:
>> b
=> :a
>> b + 1
NoMethodError: undefined method `+' for :a:Symbol
... y sin duda hay un montón de advertencias. Tal como el que usted tendría que capturar el binding
y pasarlo todo en los escenarios más complejos ...
'pass parameter by reference' in Ruby?
@ Paul.s tiene una respuesta para si se puede cambiar el punto de ser una declaración de objeto envoltorio, pero si sólo se puede controlar el punto de referencia, entonces aquí es una clase BasicReference
traté:
class BasicReference
def initialize(r,b)
@r = r
@b = b
@val = eval "#{@r}", @b
end
def val=(rhs)
@val = eval "#{@r} = #{rhs}", @b
end
def val
@val
end
end
a = 5
puts "Before basic reference"
puts " the value of a is #{a}"
b = BasicReference.new(:a, binding)
b.val = 4
puts "After b.val = 4"
puts " the value of a is #{a}"
puts " the value of b.val is #{b.val}"
Este salidas:
Before basic reference
the value of a is 5
After b.val = 4
the value of a is 4
the value of b.val is 4
Como se ha notado, la sintaxis que está utilizando no se puede hacer. Simplemente tirar esto hacia fuera allí, sin embargo se puede hacer una clase contenedora que depende de lo que realmente quiere hacer
ruby-1.8.7-p334 :007 > class Wrapper
ruby-1.8.7-p334 :008?> attr_accessor :number
ruby-1.8.7-p334 :009?> def initialize(number)
ruby-1.8.7-p334 :010?> @number = number
ruby-1.8.7-p334 :011?> end
ruby-1.8.7-p334 :012?> end
=> nil
ruby-1.8.7-p334 :013 > a = Wrapper.new(4)
=> #<Wrapper:0x100336db8 @number=4>
ruby-1.8.7-p334 :014 > b = a
=> #<Wrapper:0x100336db8 @number=4>
ruby-1.8.7-p334 :015 > a.number = 6
=> 6
ruby-1.8.7-p334 :016 > a
=> #<Wrapper:0x100336db8 @number=6>
ruby-1.8.7-p334 :017 > b
=> #<Wrapper:0x100336db8 @number=6>
Solo por el bien de la referencia.
>> a = 5
=> 5
>> a.object_id
=> 11
>> b = a
=> 5
>> b.object_id
=> 11
>> b = 4
=> 4
>> b.object_id
=> 9
>> a.object_id
=> 11
# We did change the Fixnum b Object.
>> Fixnum.superclass
=> Integer
>> Integer.superclass
=> Numeric
>> Numeric.superclass
=> Object
>> Object.superclass
=> BasicObject
>> BasicObject.superclass
=> nil
Espero que esto nos brinde a todos un poco mejor entendimiento sobre los objetos en Ruby.
Una opción en los casos en que considere que le gustaría tener operaciones de puntero directo es utilizar el método de reemplazar Hashes, Arrays & Strings.
esto es útil para cuando desea que un método devuelva una variable que un proceso que configura el método cambiará en una fecha posterior, y no desea la molestia de usar un objeto contenedor.
ejemplo:
def hash_that_will_change_later
params = {}
some_resource.on_change do
params.replace {i: 'got changed'}
end
params
end
a = hash_that_will_change_later
=> {}
some_resource.trigger_change!
a
{i: 'got changed'}
Es probablemente mejor en general, a utilizar envoltorios de objetos explícitos para estos casos, pero este patrón es útil para las especificaciones/pruebas de material de construcción asíncrona.
Suena como punteros ... No es un desarrollador de Ruby, pero no creo que los punteros estén en Ruby. – Dair
Sí, hay indicadores en Ruby. Son referencias a las variables creadas por sus tipos de clase. Aquí b apuntaba a donde está a hasta que hizo un nuevo puntero para sí mismo haciendo referencia a Fixnum 4. –
La respuesta muestra que = la asignación crea estos punteros y cuando los tipos de los mismos apuntan a la misma referencia, todo lo que es necesario es cambiar la referencia objeto y ambos mismos tipos tienen igual referencia de objeto. Tenga en cuenta por qué dicen "En Ruby, todo es un Objeto". Mucha verdad en eso. –