为什么在哈希中向数组追加一个值也会修改分配给它的另一个变量?
示例代码:
hash_of_array = { a: [] } b = hash_of_array c = hash_of_array b[:a] < { a: [1] } puts c # => { a: [1] }
为什么两个变量的数组都有1? 我只将它附加在变量b
。
试穿
- Ruby版本2.3.1,2.4.0
- Rbenv
因为b
值和c
值是同一个对象(请查看Object# object_id
):
b.object_id == c.object_id #=> true
我认识一个叫约翰的人。 有人称他为约翰尼。 约翰尼今天开枪了。 为什么约翰也被枪杀了?
foo = _something_
只需给_something_
替代名称foo
。 它不克隆它或做任何其他恶作剧。
在你的例子中,正如@AndreyDeineko所提到的, b
和c
基本上是同一个对象。
但是,不需要展示你感到困惑的行为。
重要的是他们持有对同一个数组的引用:
array = [] b = { b: array } c = { c: array } puts b == c #=> false puts b.object_id == c.object_id #=> false puts b[:b].object_id == c[:c].object_id #=> true b[:b] << 'test' pb # {:b=>["test"]} pc # {:c=>["test"]}
ruby中的所有对象都是通过引用分配的,但True,False,Nil和Fixnums除外是特殊处理的。
你可以通过查看object_id
来测试它
irb(main):001:0> a = [1,2,3] => [1, 2, 3] irb(main):002:0> b = a => [1, 2, 3] irb(main):003:0> a.object_id == b.object_id => true
要创建对象的副本,请使用.dup
。
irb(main):005:0> b = a.dup => [1, 2, 3] irb(main):006:0> a.object_id == b.object_id => false
对于您的示例,您需要深层复制,因此您可以这样做
Marshal.load(Marshal.dump(hash))
所以,
irb(main):037:0> a = {a: []} => {:a=>[]} irb(main):038:0> b = Marshal.load(Marshal.dump(a)) => {:a=>[]} irb(main):039:0> b[:a] << 1 => [1] irb(main):040:0> b => {:a=>[1]} irb(main):041:0> a => {:a=>[]}
如前所述,优秀的答案,你面临的问题是a和b是同一个对象。 如果浅拷贝就足够了,建议使用dup方法的另一个答案(后来删除)。 问题是在你的场景中,浅拷贝不够好。
我建议尝试使用full_dup gem。 这个gem添加了一个名为full_dup的新方法。 full_dup会对您的对象执行深层复制。 所以举个例子:
require 'full_dup' hash_of_array = { a: [] } b = hash_of_array.full_dup c = hash_of_array.full_dup b[:a] << 1 puts b # => { a: [1] } puts c # => { a: [] }
顺便说一下,full_dup不是速度恶魔。 当您需要该方法时,您应该使用常规dup。
哎呀; 忘了提。 我是full_dup gem的作者。