我需要遍历一个数组,并保留原始数组的副本以备将来使用。
我尝试使用a = b
创建另一个变量,但当我移动a
时,两者都会受到影响。
rb(main):001:0> a = [1,2,3,4,5]
# => [1, 2, 3, 4, 5]
irb(main):002:0> b = a
# => [1, 2, 3, 4, 5]
irb(main):003:0> c = a.shift
# => 1
irb(main):004:0> a
# => [2, 3, 4, 5]
irb(main):005:0> b
# => [2, 3, 4, 5]
irb(main):006:0> c
# => 1
有没有办法防止这种情况发生?
在Ruby中,重要的是要记住变量是对象引用,它们的行为非常像指针,所以b = a
不会复制,它是对同一对象的另一个引用。
要制作副本,您必须明确并使用dup
或clone
来实现这一点:
b = a.dup
如果你对Ruby的行为感到困惑,停下来看看你正在处理的对象:
a = [ 1 ]
b = a
a.object_id == b.object_id
# => true
它们是完全相同的对象,但当被克隆时:
b = a.dup
a.object_id == b.object_id
# => false
现在他们是独立的,至少在高层是这样。
请注意,这附带了一些注意事项,因为这只是浅拷贝:
a = [ [ 1 ] ]
b = a.dup
b[0].object_id == a[0].object_id
# => true
如果您需要一个完整的克隆,deep_clone
工具就会派上用场,它可以从各种gem中获得,但最常见的是Rails的ActiveSupport。
你会在Ruby中发现,它倾向于转向更功能性的风格,就像你想从a
中剥离一个元素并避免损坏b
:一样
a = [ 1, 2, 3, 4, 5 ]
b = a
a = a.drop(1)
# => [2, 3, 4, 5]
其中drop
跳过前N条目,并将其余条目作为副本返回:
b
# => [1, 2, 3, 4, 5]