“<<”当我尝试将此变量的值附加到另一个变量时,插入一个指向变量的指针。我该如何避免这种情况?

时间:2014-08-26 05:19:19

标签: ruby-on-rails ruby

对于凌乱的标题感到抱歉。

如果我使用静态值(rails console):

 2.1.2 :013 > h=[]
  => [] 
 2.1.2 :014 > h<<[1]
  => [[1]] 
 2.1.2 :015 > h<<[1,2]
  => [[1], [1, 2]] 
 2.1.2 :016 > h<<[1,2,3]
  => [[1], [1, 2], [1, 2, 3]] 

它按预期工作。如果我使用一个使用静态值的变量,就像这样:

 2.1.2 :018 > h=[]
  => [] 
 2.1.2 :019 > a=1
  => 1 
 2.1.2 :020 > h<<a
  => [1] 
 2.1.2 :021 > a=[1,2]
  => [1, 2] 
 2.1.2 :022 > h<<a   
  => [1, [1, 2]] 
 2.1.2 :023 > a=[1,2,3]
  => [1, 2, 3] 
 2.1.2 :024 > h<<a
  => [1, [1, 2], [1, 2, 3]] 

但如果我执行以下操作,则变量的值将替换为整个数组,就像它是一个指针一样:

 2.1.2 :036 > h=[]
  => [] 
 2.1.2 :037 > a=[]
  => [] 
 2.1.2 :038 > a<<1
  => [1] 
 2.1.2 :039 > h<<a
  => [[1]] 
 2.1.2 :040 > a<<2
  => [1, 2] 
 2.1.2 :041 > h<<a
  => [[1, 2], [1, 2]] 
 2.1.2 :042 > a<<3
  => [1, 2, 3] 
 2.1.2 :043 > h<<a
  => [[1, 2, 3], [1, 2, 3], [1, 2, 3]] 

注意h的所有值如何被a的新值替换。如果我使用&#34; h.append(X)&#34;则会发生同样的情况。如果我使用其他变量,则值不会被替换:

 2.1.2 :044 > b=[1,2,3]
  => [1, 2, 3] 
 2.1.2 :045 > b<<4
  => [1, 2, 3, 4] 
 2.1.2 :046 > h<<b
  => [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3, 4]] 

我通过使用&#34; h&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; a.to_s&#34;,但是将数值转换为字符串,当我需要对它们进行数学运算时会导致问题。我遇到的另一种选择是使用&#34; h&lt;&lt; a.inspect&#34;,除了这些值被这样的引号所包围:

 ["[1]", "[1,2]", "[1,2,3]"]

这是好的,但引号也引起了其他问题。理想情况下,我希望他们这样:

 [[1], [1,2], [1,2,3]]

有没有办法防止这种情况发生?或者,使用不同的方法将数组插入到散列/数组/ json变量中?

3 个答案:

答案 0 :(得分:3)

您可以在插入数组之前复制引用:

> h = []
> a = []
> a << 1
> h << a.dup
> a << 2
> h << a.dup
> a << 3
> h << a.dup
> h
# => [[1], [1, 2], [1, 2, 3]]

答案 1 :(得分:2)

您需要了解Ruby有效地通过引用传递参数 ¹ - 只有基本类型(如float,int,true,false和nil)是不可变的,因此不会暴露您观察到的行为。对于所有其他对象,一种可能的解决方法是使用dup

h = []
a = []
a = a.dup << 1 #=> [1]
h << a         #=> [[1]]
a = a.dup << 2 #=> [1, 2]
h << a         #=> [[1], [1, 2]]
a = a.dup << 3 #=> [1, 2, 3]
h << a         #=> [[1], [1, 2], [1, 2, 3]]
h              #=> [[1], [1, 2], [1, 2, 3]]

另一种方法是使用+=隐式返回副本。但是,右手参数必须是数组而不是单个值:

h = []
a = []
a += [1] #=> [1]
h << a   #=> [[1]]
a += [2] #=> [1, 2]
h << a   #=> [[1], [1, 2]]
a += [3] #=> [1, 2, 3]
h << a   #=> [[1], [1, 2], [1, 2, 3]]
h        #=> [[1], [1, 2], [1, 2, 3]]

¹虽然在内部,Ruby通过值传递它们,但这些值是引用

答案 2 :(得分:0)

您可以获取变量&#39; a&#39;的对象ID通过Object#object_id,它可以帮助您理解。

irb(main):060:0> a= 1
=> 1
irb(main):061:0> a.object_id
=> 3
irb(main):062:0> a= [1,2]
=> [1, 2]
irb(main):063:0> a.object_id
=> 20017440
irb(main):064:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):065:0> a.object_id
=> 19627820

变量a的object_id不同。

irb(main):066:0> a= []
=> []
irb(main):067:0> a << 1
=> [1]
irb(main):068:0> a.object_id
=> 18718920
irb(main):069:0> a << 2
=> [1, 2]
irb(main):070:0> a.object_id
=> 18718920
irb(main):071:0> a << 3
=> [1, 2, 3]
irb(main):072:0> a.object_id
=> 18718920

如果您使用&#34;&lt;&lt;&#;&#34;,变量&#39; a&#39;的object_id不会改变,如果你改变变量a的值,那么数组的所有元素都会被改变。会改变。

所以你可以使用&#39; a.dup&#39;获取对象a的浅表副本,然后将其添加到数组h。