передать массив в Array # каждый, внутри он использует ссылку или значение - PullRequest
0 голосов
/ 10 марта 2011
array1 = [0, 1]

# CASE 1:  
[array1].each do |arr| 
  arr = [3, 4] 
end

=> [0, 1]

# CASE 2:
[array1].each do |arr| 
  arr.delete_if { |ele| ele == 0 }
end

=> [[1]]

Я думал, что ruby ​​всегда передает массив по ссылке.Почему это не изменило значение массива в случае 1, но изменило его в случае 2?спасибо.

Ответы [ 3 ]

2 голосов
/ 10 марта 2011

В вашей первой ситуации все, что вы сделали, это изменили, на какой объект arr указывает - вы на самом деле не изменили оригинал. Это можно доказать с помощью следующего скрипта:

# Given our test value...
test_array = [1, 2]

# we can verify the values and the object_ids
puts "Value of `test_array`: #{test_array.inspect}"
puts "Object_id of `test_array`: #{test_array.object_id}"

# now, let's put it in a container and run it through a block
@array_container = [test_array]

@array_container.each do |arr|

  # Just to prove that `arr` points at test_array
  puts "Object_id of `arr`: #{arr.object_id}"

  # and that it's the same as the first element in our container
  puts "@container.first.object_id: #{@array_container.first.object_id}"

  # but, when we re-assign our block variable
  arr = [3, 4]

  # we get different values
  puts "Object_id of `arr`: #{arr.object_id}"
  puts "@container.first.object_id: #{@array_container.first.object_id}"
end

Какие выходы ...

Value of `test_array`: [1, 2]
Object_id of `test_array` : 2150710260

Object_id of `arr`        : 2150710260
@container.first.object_id: 2150710260

Object_id of `arr`        : 2150708040
@container.first.object_id: 2150710260

Так чем же это отличается в случае 2? В случае 2 вы фактически вызываете саморазрушающий метод, который внесет изменения в исходный объект, на который ссылается arr

0 голосов
/ 23 апреля 2012

.each просто вызывает блок с каждым элементом коллекции, к которой он вызывается (в данном случае [array1]) по очереди.Передача аргумента просто назначает его параметру.Ваш пример можно упростить до следующего:

# CASE 1:  
array1 = [0, 1]
arr = array1
arr = [3, 4]
array1

=> [0, 1]

# CASE 2:
array1 = [0, 1]
arr = array1
arr.delete_if { |ele| ele == 0 }
array1

=> [1]
0 голосов
/ 10 марта 2011

Я думаю, что ваша проблема связана с областью. Конструкция do-end на самом деле является новым блоком, поэтому, когда вы объявляете arr = [3, 4], вы создаете новый arr = [3, 4] в этом блоке. Принимая во внимание, что в случае 2 вы изменяете ссылку напрямую. Чтобы сделать то же самое в случае 1 было бы что-то вроде:

[array1].each do |arr| 
  arr.each_index do |i|
    arr[i]+=3
  end 
end

=> [[3,4]]
...