ruby变量作为同一个对象(指针?)

时间:2011-08-24 00:55:29

标签: ruby variables pointers

>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5

如何将'b'设置为实际为'a',以便在示例中,变量a也将变为4。感谢。

7 个答案:

答案 0 :(得分:6)

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

执行b = a时,b指向与a相同的对象(它们具有相同的object_id)。

执行a = some_other_thing时,a会指向另一个对象,而b保持不变。

对于Fixnumniltruefalse,您无法在不更改object_id的情况下更改值。但是,您可以更改其他对象(字符串,数组,哈希等)而不更改object_id,因为您不使用赋值(=

字符串示例:

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

数组示例:

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]

答案 1 :(得分:2)

你不能。变量持有对值的引用,而不是对其他变量的引用。

以下是您的示例代码正在执行的操作:

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

有关该主题的更深入讨论,请参阅此文章:pass by reference or pass by value

答案 2 :(得分:1)

正如已经注意到的,您正在使用的语法无法完成。只是把它扔到那里虽然你可以做一个包装类,但这取决于你真正想要做什么

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> 

答案 3 :(得分:1)

您可以使用数组:

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

这个想法基于this answer

答案 4 :(得分:1)

仅供参考。

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

我希望这能让我们更好地理解Ruby中的对象。

答案 5 :(得分:1)

如果您觉得自己想要直接指针操作,可以使用Hashes,Arrays&amp; amp;的替换方法。字符串。

当你想让一个方法返回一个变量时,这个方法很有用,该方法设置的proc将在以后改变,并且不希望使用包装器对象。

示例:

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

对于这种情况,通常可以更好地使用显式对象包装器,但是这种模式对于构建异步内容的规范/测试很有用。

答案 6 :(得分:0)

我不是Ruby专家。但是对于一个技术上疯狂的kluge ......只有当你每次使用变量时都想通过eval时才会有效:

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

请注意,直接使用b仍然会为您提供:a,并且您无法在不在eval中的表达式中使用它:

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

......当然有很多警告。例如,您必须捕获binding并在更复杂的场景中传递它...

'pass parameter by reference' in Ruby?

@ Paul.s有一个答案,如果你可以将声明点更改为包装器对象,但是如果你只能控制引用点,那么这里是我试过的BasicReference类:

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

输出:

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