什么是访问实例的好方法?

时间:2019-01-18 04:01:18

标签: ruby

如何编写我的类以访问不同对象的数组?

class ListArray
  attr_accessor :arr

  def initialize arr
    @arr = arr
  end
end

a = ListArray.new([0, 1, 2, 3])
b = ListArray.new(a.arr)
a.arr[2] = 999
b.arr[2] = 4
a.arr[2] #=> 4  ?
b.arr[2] #=> 4

当我将b.arr[2]的值更改为4时,a.arr[2]值(应为999)取值为4。

我不知道我做错了什么。

[编辑]

我的完整代码看起来像这样:

class OtherClass
   def list
end

class ListArray
   attr_accessor :arr
   def initialize arr
      @arr = arr
   end
   def putItem ...
   def getItem ...
   def cutList &bloc ...
end

a = ListArray.new obj1_other_class.list
  # obj2_other_class.list =>  [[1, 2], [3, 4], ... ]
  # [3, 4] is an item
b = ListArray.new obj2_other_class.list
a.putItem [5, 6]
c = ListArray.new a.arr
c.arr += b.arr
c.arr[1][0] = 7
      ...

如何避免对象的相同id问题?

2 个答案:

答案 0 :(得分:4)

class ListArray
  attr_accessor :arr
  def initialize(arr)
    @arr = arr
  end
  def arr_object_id
    @arr.object_id
  end
end

创建ListArray的实例,创建一个等于@arr的实例变量[0, 1, 2, 3]

a = ListArray.new [0, 1, 2, 3] 
  #=> #<ListArray:0x0000574d960e19e8 @arr=[0, 1, 2, 3]> 

让我们检查@arr的值并获取其对象ID:

a.arr
  #=> [0, 1, 2, 3] 
a.arr_object_id
  #=> 47995370802440 

现在创建另一个ListArray实例,创建其实例变量@arr并将其设置为等于a.arr的值:

b = ListArray.new(a.arr)
  #=> #<ListArray:0x0000574d9611bdf0 @arr=[0, 1, 2, 3]> 
b.arr
  #=> [0, 1, 2, 3] 
b.arr_object_id
  #=> 47995370802440

有趣的是,a.arr_object_id == b.arr_object_id。但是,这并不奇怪,因为我们将b的实例变量初始化为a的实例变量,所以它们是同一对象

接下来,将a的实例变量的值更改为[0, 1, 999, 3]

a.arr[2] = 999
a.arr
  #=> [0, 1, 999, 3] 
a.arr_object_id
  #=> 47995370802420 

检查b的实例变量的值是否已更改:

b.arr
  #=> [0, 1, 999, 3] 
b.arr_object_id
  #=> 47995370802440

之所以如此,是因为ab的实例变量@arr拥有相同的对象。

要使b的实例变量保存一个其实例变量与a相同的数组,但使两个数组成为不同的对象,请使用其实例变量创建b @arr等于a实例变量的值的副本

a = ListArray.new [0, 1, 2, 3]
  #=> #<ListArray:0x0000574d9610d818 @arr=[0, 1, 2, 3]> 
a.arr_object_id 
  #=> ...320 
b = ListArray.new(a.arr.dup)
  #=> #<ListArray:0x0000574d961143c0 @arr=[0, 1, 2, 3]> 
b.arr
  #=> [0, 1, 2, 3] 
b.arr_object_id
  #=> ...100 (different than a.arr_object_id)
a.arr[2] = 19
a.arr
  #=> [0, 1, 19, 3] 
b.arr
  #=> [0, 1, 2, 3] 

但是,等等,我们还没有结束。这是第二个示例,说明了为什么不能总是仅应用dup

a = ListArray.new [0, [1, 2], 3]
  #=> #<ListArray:0x0000574d9614b370 @arr=[0, [1, 2], 3]> 
a.arr_object_id 
  #=> ...700 
a.arr[1].object_id
  #=> ...720 
a.arr[1][1].object_id
  #=> 5 
2.object_id
  #=> 5 

b = ListArray.new(a.arr.dup)
  #=> #<ListArray:0x0000574d96119258 @arr=[0, [1, 2], 3]> 
b.arr
  #=> [0, [1, 2], 3] 
b.arr_object_id
  #=> ...160  (different than a.arr_object_id)
b.arr[1].object_id
  #=> ...720 (same as a.arr[1].object_id) 
b.arr[1][1].object_id
  #=> 5 

现在更改a.arr[1][1]的值:

a.arr[1][1] = 9
a.arr
  #=> [0, [1, 9], 3] (as expected) 
a.arr[1].object_id
  #=> ...720 (no change) 
b.arr
  #=> [0, [1, 9], 3]
b.arr[1].object_id 
  #=> ...720 (no change)

您也看到了b[1][1]的变化。这是因为a.arr[1]b.arr[1]的值对象的 contents 已被更改。现在尝试这个。

a.arr[1] = [8, 0]
a.arr
  #=> [0, [8, 0], 3] (as expected) 
a.arr[1].object_id
  #=> ...880 (a new object!) 
b.arr
  #=> [0, [1, 9], 3] (unchanged!) 
b.arr[1].object_id 
  #=> ...720 (unchanged)

对于此示例,我们需要编写:

a = ListArray.new [0, [1, 2], 3]
b = ListArray.new(a.arr.dup.map { |e| e.dup })

a.arr[1][1] = 9
a.arr
  #=> [0, [1, 9], 3] 
b.arr
  #=> [0, [1, 2], 3] (no change!)
a.arr.dup.map { |e| e.dup }相比,

a.arr被称为a.arr.dup更深的副本。如果还有更深的嵌套数组([1, [2, [3, 4]], 5]),我们将不得不dup降低到a.arr的较低级别。对于Ruby新手来说,完全理解深层副本的构造并不重要,仅需要它们就可以实现对象的重复副本的独立性。

答案 1 :(得分:3)

通过

spring stop

您实际上将b = ListArray.new a.arr 的引用转移到b,而不是值。

您可以这样做:

a.arr

检查this question,这与引用或值的参数传递有关。