我有一个类,在其中对实例变量使用Array#shift
实例方法我以为我复制了我的实例变量,但事实上我没有,实际上shift
正在改变实例变量。
例如,在我期望得到["foo", "bar", "baz"]
两次之前,给出了以下条件:
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"]
但如图所示,我的“副本”根本不是副本现在,我不确定我是否应该把我想要的叫做“复制”、“克隆”、“重复”、“深度克隆”、“深度重复”、“冻结克隆”等等。。。
我真的很困惑该搜索什么,发现一堆疯狂的尝试做什么,似乎“复制一个数组”。
然后我发现another answer实际上有一条线解决了我的问题:
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
的“副本”是有意义的。但这与:
foo = arr
foo = arr.clone
foo = arr.dup
foo = arr.deep_clone
Marshal.load # something something
# etc...
或者我看到的其他疯狂的组合?
最佳答案
这是ruby中易变性的棘手概念在核心对象方面,通常会出现数组和散列。字符串也是可变的,但这可以通过脚本顶部的标志禁用。见What does the comment "frozen_string_literal: true" do?。
在这种情况下,您可以轻松地调用dup
,deep_dup
,clone
,达到与replace
相同的效果:
['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])
就差异而言,
dup
和clone
是相同的,除了一些细微的细节-参见What's the difference between Ruby's dup and clone methods?它们与
deep_dup
的区别在于deep_dup
递归工作。例如,如果复制嵌套数组,则不会克隆内部数组: a = [[1]]
b = a.clone
b[0][0] = 2
a # => [[2]]
同样的事情也发生在散列上。
Marshal.load Marshal::dump <object>
是一种通用的深度克隆对象的方法,与deep_dup
不同,它在ruby core中。Marshal::dump
返回一个字符串,以便可以方便地将对象序列化为文件。如果你想避免像这样的意外错误,保持一个心理索引,看看哪些方法有副作用,只有在有意义的时候才调用这些方法方法名末尾的一个解释点表示它有副作用,但其他的包括unshift、push、concat、delete和pop功能性编程的很大一部分是避免副作用您可以看到https://www.sitepoint.com/functional-programming-techniques-with-ruby-part-i/
关于ruby - 使用[] .replace制作数组的副本,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41657091/