为什么我不要求红宝石改变我的数组?

时间:2019-03-20 02:59:30

标签: ruby clone

下面有两种方法:两者是相同的,只是一个clone输入,而另一个不同。

方法1

arr = [1,2,3,1,2,3]

def remove_smallest(array)
  new = array
  new.reject! {|i| i <= new.min}
  new
end

remove_smallest(arr)
#=> [2,3,2,3]
arr
#=> [2,3,2,3]

方法2

arr = [1,2,3,1,2,3]

def remove_smallest(array)
  new = array.clone
  new.reject! {|i| i <= new.min}
  new
end

remove_smallest(arr)
#=> [2,3,2,3]
arr
#=> [1,2,3,1,2,3]

在没有clone的情况下,即使我对原始数组的副本执行所有操作,该方法也会使原始输入突变。

为什么需要一种显式的clone方法来避免这种突变?

1 个答案:

答案 0 :(得分:10)

  

[...]会改变原始输入,即使我对原始数组的副本执行所有操作。

您不对副本执行操作。做的时候

new = array

它不会导致复制操作。相反,分配使new只是引用了array所引用的同一对象。因此,调用new.reject!array.reject!都没有关系,因为reject!被发送到同一接收者。

  

为什么需要一种显式的.clone方法来避免这种突变?

因为clone执行了您为=进行的复制操作。从文档中:

  

产生 obj [...]

的浅表副本

避免这种突变的另一种方法是改用非突变方法:

def remove_smallest(array)
  array.reject {|i| i <= array.min }
end

或–为避免重新计算每个步骤的最小值:

def remove_smallest(array)
  min = array.min
  array.reject {|i| i <= min }
end

您也可以使用==代替<=,因为min已经是可能的最小值。

或者,还有Array#-

def remove_smallest(array)
  array - [array.min]
end