Integer变量和Array变量之间存在奇怪的区别

时间:2011-04-12 14:58:17

标签: ruby

a = 1
def bla x
 x = x + 1
end

bla a # =>2 when I use bla to add 1, it return 2

a # => 1 but it get back to the original value

a = [1] 

但是数组

def bla x
 x << 1
end

bla a # => [1,1]

a # =>[1,1] stay in the new value 

有人可以告诉我它为什么会这样吗?

4 个答案:

答案 0 :(得分:3)

可变不可变对象之间存在差异。

  • Numerical是不可变的;换句话说,如果您拥有对象1,则无法将其值更改为212将始终是不同的对象,具有不同的对象ID。 1+1正在做的是返回新创建的2,这是与1不同的对象。

  • ArrayHashString是可变的;换句话说,如果您拥有对象[],则可以将其更改为[1]保留其标识,这就是您的代码所做的事情。即使该值现在不同,它与[]之前的对象相同。

但在您的情况下,您正在比较Fixnum#+Array#<<并声称它们不同。这并不奇怪。它们是不同的方法,为什么你们期望它们是相同的?事实上,正如mu指出的那样,如果你做a+[1],那就不会改变a。它具有与Fixnum#+相当的效果:创建一个新对象并将其返回。

您的问题应该是真正的问题:为什么没有对应Numerical#<<的行为类似于Array#<<?上面的可变与不可变的差异就是答案。

答案 1 :(得分:2)

这是因为调用<<方法将编辑数组引用的值。

如果您不希望这种情况发生,您可以这样做:

def bla x
  x + [1]
end

这可以通过将数组x与数组[1]连接起来,从此操作返回一个新数组。

或:

ruby-1.9.2-p136 :007 > bla a.dup
 => [1, 1] 
ruby-1.9.2-p136 :008 > a
 => [1] 

这将使用Object#dup,它将执行浅拷贝。

如果您需要深层副本,可以使用Object#clone

答案 2 :(得分:2)

此整数版本bla

def bla x
  x += 1
end
a = 1
bla a

更靠近你的阵列。但是,即使这个也不会改变a,因为Fixnum实例是不可变的;如果Fixnum个实例不是不可变的,那么你就会让人们改变1的值,而这只会造成很大的混乱。

此版本的数组bla

def bla x
  x + [1]
end
a = [1]
bla a

更接近你的整数1。这个array-bla将a保持不变。

您的阵列更改a,因为x << 1x.push(1)相同,而push方法会修改数组。您的array-bla看到的x是指向a所指向的同一对象的引用。

答案 3 :(得分:1)

'&LT;&LT;'运算符总是将值附加到现有变量(通过引用),但其他变量不会。