包含其他实例变量的实例变量数组并不反映对包含元素的更改

时间:2014-06-23 15:09:39

标签: ruby class instance-variables

前几天我注意到Ruby中的实例变量有一些奇怪的行为。我试图添加一个实例变量数组,包含该类的其他实例变量“属性”。该类初始化时没有任何参数,但我仍然想在初始化时创建这个数组。这是一个(精简的)类的例子:

class Foo
  attr_accessor :bar, :baz
  attr_reader :attrs

  def initialize
    @attrs = [@bar, @baz]
  end
end

这就是奇怪的地方:

f = Foo.new     #=><Foo.0x[object_id] @attrs=[nil, nil]>
f.bar = "bar"   #=>"bar"
f.baz = "baz"   #=>"baz"
f.attrs         #=>[nil, nil]

初始化时,我可以看到Foo.attrs[nil, nil]。但在更新Foo.barFoo.baz后,为什么Foo.attrs仍在返回[nil, nil]?为什么他们的新价值没有反映出来?

我认为这不是最好的方法,并找到了解决方法,但我仍然对这种行为感到好奇。

2 个答案:

答案 0 :(得分:2)

因为这就是变量的工作方式,这里和几乎所有其他编程语言都是如此。

您的数组在创建数组时包含@bar@baz 的值包含对变量本身的引用。修改一个不会修改另一个。

有效地你已经完成了这个:

x = 3;
y = x;
x = 4;
# Why doesn't y equal 4?

y不是4,因为xy共享,但不相关。将x重新分配给新值不会修改y包含的值。

如果您希望这个工作,您需要使用成员变量的当前值创建一个按需构建数组的访问器:

class Foo
  attr_accessor :bar, :baz

  def attrs
    [@bar, @baz]
  end
end

答案 1 :(得分:0)

您只需添加puts并查看会发生什么

class Foo
  attr_accessor :bar, :baz
  attr_reader :attrs

  def initialize
    @attrs = [@bar, @baz]
    puts "inside initialize"
  end
end

现在,您可以在创建Foo

的实例时看到初始化执行
f = Foo.new 
#=> inside initialize
#=> #<Foo:0x2bc1bb0 @attrs=[nil, nil]>

f.bar = "bar"   #=>"bar" , "inside initialize" not printed

如果您确实要分配它们,请创建一个setter

class Foo
  attr_accessor :bar, :baz
  attr_reader :attrs

  def initialize
    @attrs = [@bar, @baz]
    puts "inside initialize"
  end

  def bar=(v)
    @bar = v
    @attrs = [@bar,@baz]
  end

  def baz=(v)
    @baz = v
    @attrs = [@bar,@baz]
  end
end

f = Foo.new 
#=> inside initialize
#=> #<Foo:0x2bc1bb0 @attrs=[nil, nil]>

f.bar = "bar"
f.attrs #=> ["bar", nil]

f.baz = "baz"
f.attrs #=> ["bar", "baz"]