例如:
a = [1,2,3,4]
b = a
c = a.to_a
a.insert(0,0) #=> [0,1,2,3,4]
b #=> [0,1,2,3,4]
c #=> [0,1,2,3,4]
为什么数组的输出b
和输出c
是一样的?如果我想获得 array 的副本a
,而不是参考副本,我应该使用哪种方法?
为什么数组 b 和 c 的输出是一样的?
因为所有三个局部变量都引用了相同的对象,如下所示:
a = [1,2,3,4]
b = a
c = a.to_a
a.object_id
# => 72187200
b.object_id
# => 72187200
c.object_id
# => 72187200
如果我想获取数组 a 的副本,而不是参考,我应该使用哪种方法?
然后使用a.dup
.Here 记录Object#dup
a = [1,2,3,4]
b = a.dup
c = a.dup
a.object_id
# => 82139270
b.object_id
# => 82139210
c.object_id
# => 82134600
a.insert(0,0) # => [0, 1, 2, 3, 4]
b # => [1, 2, 3, 4]
c # => [1, 2, 3, 4]
Array#to_a
说:返回自我。如果在 Array 的子类上调用,则将接收者转换为 Array 对象。
因此,根据您的需要,它不会有帮助。
这是因为Array#to_a
返回self
,所以两个变量都包含对同一个 Array 对象的引用。为了获得具有相同内容的新数组,您可以使用dup
或clone
(阅读和之间的区别dup
clone
):
a = [1, 2, 3]
b = a.dup
a << 4
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3]
但是请注意,相同的对象引用存储在新数组中。这意味着如果你改变对象本身,它们仍然会在两个数组中发生变化:
a = ['foo', 'bar']
b = a.dup
a[0] << 'baz'
a #=> ["foobaz", "bar"]
b #=> ["foobaz", "bar"]
这是因为dup
和clone
是浅拷贝。
Array#to_a
返回接收器。这就是为什么b
和c
指的是同一件事。关于为什么to_a
返回原始数组,原则上,它可以以一种或另一种方式定义,但我想一个用例to_a
是将它应用于可能nil
确保它成为数组的变量。
some_value.to_a # => `[]` if `some_value` is `nil`
在这种用例中,如果接收器已经是一个数组,则无需将数组替换为另一个数组。这在性能上会更可取。
原因是变量只是对数据的引用。变量存储在内存中;变量保存它们在内存中所在位置的地址。所以当你这样做时:
a = b
这两个变量指向同一个内存位置,因此如果你 alter a
,b
也会被改变,因为它是同一个对象。
有几种方法可以强制 Ruby 创建对象的另一个副本。最流行的是dup
LBg提到的方法。但是请注意,它只是创建一个浅拷贝。如果你运行:
a = ['foo','bar', []]
b = a.dup
a << 'blah'
b #=> ['foo', 'bar', []] as expected but
b[3] << blah
a #=> ['foobar', 'bar', ['blah]]
原因是数组实际上是一个引用数组,嵌套数组在执行时没有重复dup
,所以它们是同一个对象。
要创建对象的深层副本,您可以使用 Marshall 模块:
b = Marshal.load(Marshal.dump(a))
但是,通常您实际上并不需要这样做。此外,某些对象不能被复制(例如符号)。
你可以做
b = a.dup
旧帖子
如果没有更简单的方法,你可以试试这个
b = a.map {|x| x}
有用
1.9.3-p448 :001 > a = [1,2,3] => [1, 2, 3]
1.9.3-p448 :002 > b = a => [1, 2, 3]
1.9.3-p448 :003 > c = a.map{|x| x} => [1, 2, 3]
1.9.3-p448 :004 > a<<0 => [1, 2, 3, 0]
1.9.3-p448 :005 > b => [1, 2, 3, 0]
1.9.3-p448 :006 > c => [1, 2, 3]
但它是一个浅拷贝。
根据这篇文章,a.dup
是更简单的方法。