搞错了数组

时间:2018-01-17 00:48:45

标签: arrays ruby

我将数组sequence保存到reset。我从sequence删除了每个元素,执行了一项操作,然后将sequence重置为原来的状态。

reset = sequence
(0..sequence.length).each do |i|
  puts "Sequence #{sequence}, index is #{i}.  Deleting #{sequence[i]}"
  sequence.delete_at(i)
  puts "New sequence is #{sequence.inspect}, sorted makes #{sequence.sort}, unique makes #{sequence.uniq}"
  return true if sequence.sort == sequence && sequence.uniq == sequence
  puts "This is reset before the sequence = reset: #{reset.inspect}"
  sequence = reset
  puts "Resetting sequence. Reset is #{reset.inspect}, sequence is #{sequence.inspect}"
  dummy = gets.chomp
end

然后,sequence发生的事情也发生在reset。这是一些输出:

Sequence [1, 1, 1, 2, 3], index is 0.  Deleting 1
New sequence is [1, 1, 2, 3], sorted makes [1, 1, 2, 3], unique makes [1, 2, 3]
This is reset before the sequence = reset: [1, 1, 2, 3]
Resetting sequence. Reset is [1, 1, 2, 3], sequence is [1, 1, 2, 3]

当我只是命令它从reset删除时,它正在捣乱sequence。情况并非reset = sequence在循环内部。是什么赋予了?该循环应该在oldarray.size处中断,在其中将元素推入新数组。但令人费解的是,它也将相同的数字推送到同一个数组中,从而创建了一个无限循环。

2 个答案:

答案 0 :(得分:3)

resetsequence 是相同的数组=运算符不会复制数组或其他对象的内容;它创建了对同一个数组的新引用。

例如,请在irb

中尝试此操作
irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> b = a
=> [10, 20]
irb(main):003:0> a
=> [10, 20]
irb(main):004:0> b
=> [10, 20]
irb(main):005:0> a.push( 30 )
=> [10, 20, 30]
irb(main):006:0> b.push( 40 )
=> [10, 20, 30, 40]
irb(main):007:0> a
=> [10, 20, 30, 40]
irb(main):008:0> b
=> [10, 20, 30, 40]

在方法调用中传递数组或任何对象时也是如此。该方法没有获得对象数据的单独副本;它接收对同一对象的引用:

irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> def foo( x );  x.push( 30 );  end
=> :foo
irb(main):003:0> foo( a )
=> [10, 20, 30]
irb(main):004:0> a
=> [10, 20, 30]

请注意,foo并未修改其x参数,它还修改了传递给它的a,因为x和{{1}两个都是对同一个数组的引用。

如果您想制作数组的副本以使其上的操作独立于原始数据,则可以使用adup

clone

许多语言都是这样的;赋值运算符或函数参数不会复制任何数据,只是创建对同一数据的新引用。

这是Python中的相同示例:

irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> b = a.clone
=> [10, 20]
irb(main):003:0> a
=> [10, 20]
irb(main):004:0> b
=> [10, 20]
irb(main):005:0> a.push( 30 )
=> [10, 20, 30]
irb(main):006:0> b.push( 40 )
=> [10, 20, 40]
irb(main):007:0> a
=> [10, 20, 30]
irb(main):008:0> b
=> [10, 20, 40]

并在JavaScript中:

>>> a = [ 10, 20 ]
>>> b = a
>>> a
[10, 20]
>>> b
[10, 20]
>>> a.append( 30 )
>>> b.append( 40 )
>>> a
[10, 20, 30, 40]
>>> b
[10, 20, 30, 40]

答案 1 :(得分:0)

假设我们写

sequence = [1, 1, 1, 2, 3]
reset = sequence
  #=> [1, 1, 1, 2, 3]

变量sequencereset不仅保持相同的值,而且保持相同的对象:

sequence.object_id
  #=> 4044000
reset.object_id
  #=> 4044000

请注意,变量没有对象ID;它们的价值观 - Ruby对象 - 具有独特的ID(参见Object#object_id)。当我们写sequence.object_id时,sequence会返回[1, 1, 1, 2, 3],然后会返回[1, 1, 1, 2, 3].object_id #=> 4044000

如果更改了对象[1, 1, 1, 2, 3],则两个变量的值都将等于更改的对象。

sequence.replace [1, 4]
  #=> [1, 4]
sequence.object_id
  #=> 4044000
reset
  #=> [1, 4]
reset.object_id
  #=> 4044000

另一方面,如果我们将这些变量中的任何一个设置为等于差异对象(具有不同的对象id),则另一个变量的值不受影响。

sequence = [99, 31]
sequence.object_id
  #=> 5564720
reset
  #=> [1, 4]
reset.object_id
  #=> 4044000