ruby variable as same object (pointers?)

前端 未结 7 987
-上瘾入骨i
-上瘾入骨i 2021-01-01 03:22
>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5

how can I set \'b\' to actually be \'a\' so that in the exa

相关标签:
7条回答
  • 2021-01-01 03:33

    You can't. Variables hold references to values, not references to other variables.

    Here's what your example code is doing:

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

    See this article for a more in-depth discussion of the topic: pass by reference or pass by value.

    0 讨论(0)
  • 2021-01-01 03:34

    One option in cases where you feel you would like to have direct pointer operations is to use the replace method of Hashes, Arrays & Strings.

    this is useful for when you would like to have a method return a variable that a proc the method sets up will change at a later date, and don't want the annoyance of using a wrapper object.

    example:

    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'}
    

    It's probably better generally to use explicit object wrappers for such cases, but this pattern is useful for building specs/tests of asynchronous stuff.

    0 讨论(0)
  • 2021-01-01 03:34

    I'm no Ruby expert. But for a technically crazy kluge...that would only work if you felt like going through eval every time you worked with a variable:

    >> a = 5
    => 5
    >> b = :a
    => :a
    >> eval "#{b} = 4"
    => 4
    >> eval "#{a}"
    => 4
    >> eval "#{b}"
    => 4
    

    Note that a direct usage of b will still give you :a and you can't use it in expressions that aren't in eval:

    >> b
    => :a
    >> b + 1
    NoMethodError: undefined method `+' for :a:Symbol
    

    ...and there are certainly a ton of caveats. Such as that you'd have to capture the binding and pass it around in more complex scenarios...

    'pass parameter by reference' in Ruby?

    @Paul.s has an answer for if you can change the point of declaration to be a wrapper object, but if you can only control the point of reference then here's a BasicReference class I tried:

    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}"
    

    This outputs:

    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
    
    0 讨论(0)
  • 2021-01-01 03:42

    As has been noted the syntax you are using can not be done. Just throwing this out there though you could make a wrapper class it depends what you actually want to do

    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> 
    
    0 讨论(0)
  • 2021-01-01 03:46
    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
    

    When you do b = a, b points to the same object as a (they have the same object_id).

    When you do a = some_other_thing, a will point to another object, while b remains unchanged.

    For Fixnum, nil, true and false, you cannot change the value without changing the object_id. However, you can change other objects (strings, arrays, hashes, etc.) without changing object_id, since you don't use the assignment (=).

    Example with strings:

    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
    

    Example with arrays:

    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]
    
    0 讨论(0)
  • 2021-01-01 03:46

    Just for the sake of reference.

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

    I hope this gives us all a little better understanding about objects in Ruby.

    0 讨论(0)
提交回复
热议问题