为什么在哈希中向数组追加一个值也会修改分配给它的另一个变量?

示例代码:

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所提到的, bc基本上是同一个对象。

但是,不需要展示你感到困惑的行为。

重要的是他们持有对同一个数组的引用:

 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的作者。