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



前几天我注意到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] ?为什么他们的新价值观没有得到体现?

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

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

你的数组包含@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

您可以简单地添加一个puts,看看会发生什么

class Foo
  attr_accessor :bar, :baz
  attr_reader :attrs
  def initialize
    @attrs = [@bar, @baz]
    puts "inside initialize"
  end
end

现在你可以看到当你创建Foo

实例时,initialize会被执行
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"]

相关内容

  • 没有找到相关文章

最新更新