数组/哈希奇怪的行为

时间:2014-09-28 21:15:32

标签: ruby-on-rails ruby arrays hash

我进行了以下测试:

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值推入数组中。这里发生了什么?

2 个答案:

答案 0 :(得分:2)

b不是哈希。它是哈希的引用。在其他地方推送引用不会使它指向一个新实例。

使用b.dup将哈希显式复制到您想要的位置。

有时甚至可能还不够,因为同样适用于内部哈希值:新哈希内部将具有相同的引用,它是所谓的“浅拷贝”

(这里我声称字符串在Ruby中是不可变的,但是@BroiSatse指出它不是真的,他是对的,请按照评论中的链接。)

无论如何,解释是相似的:将新字符串分配到变量中会为字符串生成新引用(不会改变现有字符串),将新值写入散列不会生成新的散列引用(改为改变现有散列)。

答案 1 :(得分:2)

您需要了解ruby变量和数组的工作原理。变量保存对象的引用,这意味着如果你这样做:

a = b = []

ab都引用了一些对象!

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']