我进行了以下测试:
irb(main):023:0> a=[]
=> []
irb(main):024:0> b="1"
=> "1"
irb(main):025:0> a.push(b)
=> ["1"]
irb(main):026:0> a
=> ["1"]
irb(main):027:0> b="2"
=> "2"
irb(main):028:0> a
=> ["1"]
到目前为止一切顺利。现在,但只要我将b更改为哈希:
irb(main):012:0> a=[]
=> []
irb(main):013:0> b={}
=> {}
irb(main):014:0> b[:file]="one"
=> "one"
irb(main):015:0> a.push(b)
=> [{:file=>"one"}]
irb(main):016:0> a
=> [{:file=>"one"}]
irb(main):017:0> b[:file]="two"
=> "two"
irb(main):018:0> a
**=> [{:file=>"two"}]**
我甚至没有将b值推入数组中。这里发生了什么?
答案 0 :(得分:2)
b
不是哈希。它是哈希的引用。在其他地方推送引用不会使它指向一个新实例。
使用b.dup
将哈希显式复制到您想要的位置。
有时甚至可能还不够,因为同样适用于内部哈希值:新哈希内部将具有相同的引用,它是所谓的“浅拷贝”
(这里我声称字符串在Ruby中是不可变的,但是@BroiSatse指出它不是真的,他是对的,请按照评论中的链接。)
无论如何,解释是相似的:将新字符串分配到变量中会为字符串生成新引用(不会改变现有字符串),将新值写入散列不会生成新的散列引用(改为改变现有散列)。
答案 1 :(得分:2)
您需要了解ruby变量和数组的工作原理。变量保存对象的引用,这意味着如果你这样做:
a = b = []
a
和b
都引用了一些对象!
a << 1
b #=> [1]
数组只不过是一个同时包含许多引用的对象。但同样,他们只是引用对象,所以如果你这样做:
a = {}
b = [a]
然后b[0]
和a
变量引用同一个对象。
a[:foo] = :bar
b #=> [{:foo => :bar}]
现在,在第一个示例中,它似乎工作方式不同的原因是赋值不会修改对象,而是更改引用本身。
a = []
b = '1'
a.push(b)
现在,a[0]
和b
都指向同一个对象。但是如果你这样做:
b = '2'
您创建了一个新字符串,并为变量b
更改了引用,但a[0]
仍在引用旧字符串。但是,如果不是更改引用,则执行一些修改方法:
b.replace('2')
你会看到它会给你:
a #=> ['2']