【问题标题】:Instance variable array containing other instance variables doesn't reflect changes to contained elements包含其他实例变量的实例变量数组不反映对包含元素的更改
【发布时间】:2014-08-13 16:40:47
【问题描述】:

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

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

【问题讨论】:

    标签: ruby class instance-variables


    【解决方案1】:

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

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

    【讨论】:

    • 你知道,出于某种原因,我说服自己这是实例变量独有的问题。返回并使用局部变量进行测试会产生相同的结果。而现在我觉得有些愚蠢。是的,这就是我最终使用的解决方案!谢谢。
    • 好答案。或许值得注意:x = 3; x.object_id #=&gt; 7; y = x; y.object_id #=&gt; 7; x = 4; x.object_id #=&gt; 9; y.object_id #=&gt; 7.
    【解决方案2】:

    您可以简单地添加一个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"]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-22
      • 2012-05-20
      • 2020-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多