Почему этот Ruby не сломается при каждом цикле?

У меня есть следующий код в одном из моих личных проектов:

def allocate(var, value) # Allocate the variable to the next available spot. 
  @storage.each do |mem_loc|
    if mem_loc.free?
      mem_loc.set(var, value) # Set it then break out of the loop.
      break
    end
  end
end

Каждый элемент в массиве хранения является объектом, который отвечает на запрос free? и установить. То, что я пытаюсь сделать, это циклически перемещаться по массиву в поисках следующего свободного (пустого) объекта для установки переменной. Моя проблема в том, что это просто перебирает каждый объект и устанавливает их все. Я неправильно использую функцию break?

Проверяя ее, я вызываю следующее:

store.allocate(:a, 10)
store.allocate(:b, 20)

Таким образом, store[1] должен быть установлен на: b и 20. Но когда я вывожу содержимое, его значение равно 10, как и остальная часть массива.


person bennybdbc    schedule 12.08.2010    source источник
comment
Он работает на Ruby 1.9.2dev. Я только что протестировал. Я не уверен насчет Ruby 1.8.x.   -  person Daniel O'Hara    schedule 12.08.2010
comment
@floatless nums.each {|x| if (x % 2 == 0) then puts "#{x} is even"; break; end } отлично работает на Ruby 1.8.7.   -  person Telemachus    schedule 12.08.2010
comment
Насколько я понимаю, вы хотите просмотреть массив пока не найдете первый свободный объект, установите его и остановитесь. Это правильно? И что на самом деле происходит, так это то, что каждый (?) элемент проходит проверку на free? и устанавливается, но цикл each никогда не прерывается? Это оно?   -  person Telemachus    schedule 12.08.2010
comment
Вместо каждого/если/разрыва используйте find: @storage.find(&:free?).set(var, value)   -  person Lars Haugseth    schedule 12.08.2010


Ответы (1)


Я считаю, что нашел ошибку, и на самом деле ее не было в приведенном выше коде. Когда я настроил массив хранения, я сделал так:

@storage = [Memory_location.new] * 1000

Полагая, что это создаст 1000 различных объектов. Я думаю, что на самом деле произошло то, что он создал 1000 ссылок на один и тот же объект, поэтому, когда я изменил одну из них, я изменил их все. Я мог бы доказать это, используя метод puts в двух разных местах массива, и оба они возвращали:

#{Memory_location:0x2bc8b74}
person bennybdbc    schedule 12.08.2010
comment
Вместо этого попробуйте 1000.times { @storage << Memory_location.new }. - person Telemachus; 12.08.2010
comment
На самом деле есть способ создавать новые объекты, передавая блок. @storage = Array.new(1000){ MemoryLocation.new } - person Chubas; 12.08.2010
comment
Еще один способ: @storage = (1..1000).map { MemoryLocation.new } - person Lars Haugseth; 13.08.2010