使用 [].replace 复制数组 [英] Use [].replace to make a copy of an array
问题描述
我有一个类,我在一个实例变量上使用了 Array#shift
实例方法.我以为我制作了我的实例变量的副本",但实际上我没有,shift
实际上是在更改实例变量.
I have a class where I was using the Array#shift
instance method on an instance variable. I thought I made a "copy" of my instance variable but in fact I hadn't and shift
was actually changing the instance variables.
例如,在我期望得到 ["foo", "bar", "baz"]
之前,给定以下内容:
For example, before I would have expected to get ["foo", "bar", "baz"]
both times given the following:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["bar", "baz"]
结果:
["foo", "bar", "baz"]
["bar", "baz"]
但如图所示,我的副本"根本不是真正的副本.现在,我不确定是否应该将我想要的称为副本"、克隆"、复制"、深度克隆"、深度复制"、冷冻克隆"等......
But as shown my "copy" wasn't really a copy at all. Now, I'm not sure if I should be calling what I want a "copy", "clone", "dup", "deep clone", "deep dup", "frozen clone", etc...
我真的很困惑要搜索什么,并发现了一堆疯狂的尝试来做看起来像制作数组副本"的事情.
I was really confused about what to search for and found a bunch of crazy attempts to do what seems like "making a copy of an array".
然后我找到了另一个答案,其中一行字解决了我的问题:
Then I found another answer with literally one line that solved my problem:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = [].replace arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["foo", "bar", "baz"]
输出:
["foo", "bar", "baz"]
["foo", "bar", "baz"]
我知道 Array#replace
是在 Array
的实例上调用的实例方法,该实例恰好是一个空数组(例如 foo =["cats", "and", "dogs"].replace arr
仍然有效)并且我得到实例变量 @arr
的副本"是有道理的.
I understand that Array#replace
is an instance method being called on an instance of Array
that happens to be an empty array (so for example foo = ["cats", "and", "dogs"].replace arr
will still work) and it makes sense that I get a "copy" of the instance variable @arr
.
但这与以下有何不同:
foo = arr
foo = arr.clone
foo = arr.dup
foo = arr.deep_clone
Marshal.load # something something
# etc...
或者我在 SO 上看到的 dup
和 map
和 inject
的任何其他疯狂组合?
Or any of the other crazy combinations of dup
and map
and inject
that I'm seeing on SO?
推荐答案
这是 ruby 中可变性的棘手概念.就核心对象而言,这通常与数组和散列有关.字符串也是可变的,但是可以通过脚本顶部的标志来禁用它.请参阅评论frozen_string_literal: true"是什么意思?.
This is the tricky concept of mutability in ruby. In terms of core objects, this usually comes up with arrays and hashes. Strings are mutable as well, but this can be disabled with a flag at the top of the script. See What does the comment "frozen_string_literal: true" do?.
在这种情况下,您可以轻松调用dup
、deep_dup
、clone
,达到与replace
相同的效果:
In this case, you can call dup
, deep_dup
, clone
easily to the same effect as replace
:
['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])
在差异方面,dup
和 clone
除了一些细微的细节之外是相同的 - 参见 Ruby 的 dup 和 clone 方法有什么区别?
In terms of differences, dup
and clone
are the same except for some nuanced details - see What's the difference between Ruby's dup and clone methods?
这些和 deep_dup
的区别在于 deep_dup
递归地工作.例如,如果您复制嵌套数组,则不会克隆内部数组:
The difference between these and deep_dup
is that deep_dup
works recursively. For example if you dup a nested array, the inner array will not be cloned:
a = [[1]]
b = a.clone
b[0][0] = 2
a # => [[2]]
同样的事情发生在哈希上.
The same thing happens with hashes.
Marshal.load Marshal::dump
是深度克隆对象的通用方法,与 deep_dup
不同,它位于 ruby 核心中.Marshal::dump
返回一个字符串,因此它可以方便地将对象序列化到文件中.
Marshal.load Marshal::dump <object>
is a general approach to deep cloning objects, which, unlike deep_dup
, is in ruby core. Marshal::dump
returns a string so it can be handy in serializing objects to file.
如果你想避免这样的意外错误,请记住哪些方法有副作用,并且只在有意义的时候调用它们.方法名称末尾的解释点表示它有副作用,但其他包括 unshift、push、concat、delete 和 pop.函数式编程的很大一部分是避免副作用.你可以看到 https://www.sitepoint.com/函数式编程技术与 ruby-part-i/
If you want to avoid unexpected errors like this, keep a mental index of which methods have side-effects and only call those when it makes sense to. An explanation point at the end of a method name indicates that it has side effects, but others include unshift, push, concat, delete, and pop. A big part of fuctional programming is avoiding side effects. You can see https://www.sitepoint.com/functional-programming-techniques-with-ruby-part-i/
这篇关于使用 [].replace 复制数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!