ruby变量作为同一个对象(指针?)
>> a = 5 => 5 >> b = a => 5 >> b = 4 => 4 >> a => 5
如何将’b’设置为’a’,以便在示例中,变量a也将变为4。 谢谢。
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
指向与b
相同的对象(它们具有相同的object_id
)。
当你执行a = some_other_thing
,a将指向另一个对象,而b
保持不变。
对于Fixnum
, nil
, true
和false
,您无法在不更改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 pa #=> [1] pb #=> [1] a << 2 # changing a pa #=> [1, 2] pb #=> [1, 2] a += [3] # assigning a pa #=> [1, 2, 3] pb #=> [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).
有关该主题的更深入讨论,请参阅此文章: 按引用传递或按值传递 。
如前所述,您使用的语法无法完成。 只是把它扔到那里虽然你可以做一个包装类,但这取决于你真正想要做什么
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) => # ruby-1.8.7-p334 :014 > b = a => # ruby-1.8.7-p334 :015 > a.number = 6 => 6 ruby-1.8.7-p334 :016 > a => # ruby-1.8.7-p334 :017 > b => #
你可以使用数组:
a = [5] b = a b[0] = 4 puts a[0] #=> 4
这个想法是基于这个答案 。
只是为了参考。
>> 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中的对象。
在您认为要进行直接指针操作的情况下,一种选择是使用哈希,数组和字符串的替换方法。
当你想让一个方法返回一个变量时,这个方法很有用,该方法设置的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'}
对于这种情况,通常可以更好地使用显式对象包装器,但是这种模式对于构建异步内容的规范/测试很有用。
我不是Ruby专家。 但对于一个技术上疯狂的kluge …只有当你每次使用变量时eval
通过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
并在更复杂的场景中传递它…
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