Как мне реализовать базовый класс Enumerator? - PullRequest
1 голос
/ 13 октября 2011

Я пытаюсь понять, как работает класс Enumerator. В частности, я не знаю, как создается объект-получатель и передается в блок кода, который принимает конструктор.

Вот моя первая попытка:

class MyEnumerator
  def initialize(&block)
    @block = block
  end 
  def next()
    @block.call self
  end 
  def yield(*args)
    args
  end 
end


num_gen = MyEnumerator.new do |yielder|
  (1..10).each { |num| yielder.yield num }
end

5.times { p num_gen.next }

Это не работает, конечно, потому что я не знаю, как продвигать счетчик. Может ли кто-нибудь помочь мне понять, как я могу это реализовать?

Ответы [ 2 ]

2 голосов
/ 13 октября 2011

Вы должны использовать какой-то механизм продолжения .Проверьте:

http://www.ruby -doc.org / docs / ProgrammingRuby / html / ref_c_continuation.html

http://ruby -doc.org / docs /ProgrammingRuby / html / ref_m_kernel.html # Kernel.callcc

Кроме того, реализовать перечислители с волокнами должно быть довольно тривиально (но, возможно, они слишком «высокого уровня», если вы хотите понять весьтогда попробуйте продолжить):

http://www.ruby -doc.org / core-1.9.2 / Fiber.html

1 голос
/ 13 октября 2011

Вот один из способов создания базового перечислителя (обновлен предложением Tokland):

class MyEnumerator
  def initialize
    @fiber = Fiber.new { yield Fiber }
  end

  def next
    @fiber.resume
  end
end

Использование:

>> num_gen = MyEnumerator.new { |f| (1..10).each { |x| f.yield x } }
=> #<MyEnumerator:0x007fd6ab8f4b28 @fiber=#<Fiber:0x007fd6ab8f4ab0>>
>> num_gen.next
=> 1
>> num_gen.next
=> 2
>> num_gen.next
=> 3
>> num_gen.next
=> 4
...