2011-08-24 21 views
5
>> 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?)

+2

Suena como punteros ... No es un desarrollador de Ruby, pero no creo que los punteros estén en Ruby. – Dair

+0

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. –

+0

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. –

Respuesta

5
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] 
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.

+0

¿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

+0

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

+0

¡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. –

0

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 
1

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> 
1

Puede utilizar matrices:

a = [5] 
b = a 
b[0] = 4 
puts a[0] #=> 4 

Esta idea se basa en this answer.

1

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.

1

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.

Cuestiones relacionadas