【发布时间】:2017-05-30 03:39:32
【问题描述】:
我有一个类,我在实例变量上使用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"]
但如图所示,我的“副本”根本不是真正的副本。现在,我不确定我是否应该将我想要的东西称为“副本”、“克隆”、“dup”、“深度克隆”、“深度复制”、“冷冻克隆”等......
我真的很困惑要搜索什么,并发现了一堆疯狂的尝试来做看似“制作数组的副本”的事情。
然后我发现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...
或者我在 SO 上看到的 dup 和 map 和 inject 的任何其他疯狂组合?
【问题讨论】:
-
这些方法之间的很多区别在于新数组中的对象是原始对象的副本还是两个数组都指向相同的对象。
-
需要注意的一点:在 ruby 中分配一个变量永远不会复制它,它只是创建一个指向该值的指针。因此,如果
arr = [1,3,4]并且您分配了x = arr,您只会为原始数组创建另一个“名称”。
标签: ruby