ruby - 为什么 ruby​​ 在我不要求时改变我的数组?

标签 ruby clone

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

方法一

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]

方法二

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 方法来避免这种突变?

最佳答案

[...] will mutate the original input even if I perform all operations on a copy of the original array.

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

new = array

它不会导致复制操作。相反,作业使 new简单地引用同一个对象 array指的是。因此,调用 new.reject! 并不重要或 array.reject!因为reject!被发送到同一个接收者。

Why is an explicit .clone method needed to avoid this mutation?

因为 clone 执行您为 = 假定的复制操作.来自文档:

Produces a shallow copy of 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

关于ruby - 为什么 ruby​​ 在我不要求时改变我的数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55252912/

相关文章:

linux - 如何在停止状态下 fork Linux 进程?

git - 如何在 git clone --reference 之后分离替代品?

ruby - ljust 可以在每个 block 中使用吗?

ruby-on-rails - Rails 去除除数字逗号和小数点以外的所有内容

ruby-on-rails - 用于小型照片应用程序的 Rails 托管

java - Intellij Idea 中的 Github 克隆

ruby - 从 Ruby 脚本创建 Gist

ruby-on-rails - ActiveModel::MissingAttributeError 在部署后发生,然后在一段时间后消失

java - 如何克隆被声明为抽象父类(super class)的对象?

Mysql用主键克隆行