深度复制对象Ruby

时间:2017-08-20 23:33:28

标签: ruby clone deep-copy tic-tac-toe dup

我完成了tic tac toe的佩奇,正在努力改进我的电脑播放器。这需要从旧板对象创建新板对象的副本。我无法创建电路板的深层副本。

以下是相关代码:

  Class Board
  attr_accessor :grid

  def initialize(grid = Array.new(3){ Array.new(3)})
    @grid = grid
  end

  def place_mark(cords, sym)
    self[cords] = sym
    @grid 
  end

  def [](pos)
    row, col = pos
    @grid[row][col]
  end

  def []=(pos, mark)
    row, col = pos
    @grid[row][col] = mark
  end

 def new_state
    grid = @grid.dup
    Board.new(grid)
  end
end 

board = Board.new
new_state = board.new_state # ==> A different object
new_state.place_mark([0,0], :X) # ==> Object with x placed at 0,0
board # ==> Object with x placed at 0,0

现在,当我实现new_state然后在new_state上放置一个标记时,它还会在重复的状态上放置一个标记。

我明白为什么如果我设置我的new_state只是复制对象它就行不通。但我不明白为什么我当前的实现不起作用。我应该存储当前对象的网格,然后使用相同的网格创建一个新对象。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

在Ruby中,dup生成一个浅层克隆,并且不会复制它们引用的对象。由于entropy是一个数组数组,因此不会复制@grid数组中的每个数组。这可能不太清楚,所以希望代码有所帮助:

@grid

所以内部数组是同一个对象,从一个地方修改它会修改引用它的所有内容。但是,如果你修改了'外部'数组,它的工作方式与您期望的一样:

grid = [ [:first_row], [:second_row] ]
copy = grid.dup
grid.object_id == copy.object_id # => false, so you have a different array
grid[0].object_id == copy[0].object_id # => true, so the inner array is the same

copy[0][0] = :test_change
grid # => [[:test_change], [:second_row]]
copy # => [[:test_change], [:second_row]]

所以,了解这一切,希望你能更清楚地解决这个问题,你只需要打电话给copy[0] = [:updates_correctly] copy # => [[:updates_correctly], [:second_row]] grid # => [[:test_change], [:second_row]] 内部'阵列。我们也会在这里使用dup,这会返回一个新的数组,因此我们不需要在外部'上调用collect。数组:

dup

但是如果我们改为使用字符串,那些数组的元素仍然不是不同的对象:

copy = grid.collect(&:dup) # => [[:test_change], [:second_row]]
copy[0][0] = :another_change
copy # => [[:another_change], [:second_row]]
grid # => [[:test_change], [:second_row]]

并修改了字符串,我们最终改变了两者:

grid = [ ['first row'] ]
copy = grid.collect(&:dup)

你需要走多远取决于你的特殊需求。

所以, TL; DR 您需要将copy[0][0].upcase! copy # => [["FIRST ROW"]] grid # => [["FIRST ROW"]] 更改为:

new_state

它应该有用。