Frage

Diese Frage ist nicht, wie Enumeratoren zu verwenden, in Ruby 1.9.1, sondern ich bin gespannt, wie sie funktionieren. Hier ist ein Code:

class Bunk
  def initialize
    @h = [*1..100]
  end

  def each
    if !block_given?
      enum_for(:each)
    else
      0.upto(@h.length) { |i|
        yield @h[i]
      }
    end
  end
end

In dem obigen Code, den ich e = Bunk.new.each verwenden kann, und dann e.next, e.next jedes aufeinanderfolgende Element zu erhalten, aber wie genau er die Ausführung Aussetzung und dann an der richtigen Stelle wieder aufzunehmen?

Ich bin mir bewusst, dass, wenn die Ausbeute bei der 0.upto mit Fiber.yield ersetzt wird, dann ist es leicht zu verstehen, aber das ist hier nicht der Fall. Es ist eine gute alte yield, so wie funktioniert es?

ich enumerator.c aussehen, aber es ist wiehern für mich unverständlich. Vielleicht Fasern verwendet wird, könnte jemand eine Implementierung in Ruby bieten, nicht 1.8.6 Stil Fortsetzung basierte Enumeratoren, das macht alles klar?

War es hilfreich?

Lösung

Hier ist ein einfacher Ruby-Enumerator, Fasern und soll so ziemlich verhalten sich wie das Original verwendet:

class MyEnumerator
  include Enumerable

  def initialize(obj, iterator_method)
    @f = Fiber.new do
      obj.send(iterator_method) do |*args|
        Fiber.yield(*args)
      end
      raise StopIteration
    end
  end

  def next
    @f.resume
  end

  def each
    loop do
      yield self.next
    end
  rescue StopIteration
    self
  end
end

Und bevor jemand beschwert sich über Ausnahmen als Flusskontrolle. Die wirkliche Enumerator wirft StopIteration am Ende auch so ich emuliert nur das ursprüngliche Verhalten

Verbrauch:

>> enum = MyEnumerator.new([1,2,3,4], :each_with_index)
=> #<MyEnumerator:0x9d184f0 @f=#<Fiber:0x9d184dc>
>> enum.next
=> [1, 0]
>> enum.next
=> [2, 1]
>> enum.to_a
=> [[3, 2], [4, 3]]

Andere Tipps

Eigentlich in Ihrer E = Bunk.new.each die else-Klausel wird zunächst nicht ausgeführt. Statt der ‚if! Block_given‘ Klausel ausführt und gibt eine Enumeratorobjekt. Das Enumeratorobjekt tut hält ein Faser Objekt intern. (Zumindest das ist, was es wie in enumerator.c aussieht)

Wenn Sie e.each nennen es wird ein Verfahren auf einem enumerator Aufruf, die intern eine Faser zur Verfolgung ihrer Ausführungskontext zu halten. Diese Methode ruft die Bunk.each Methode, um die Fasern Ausführungskontext verwenden. Der Bunk.each Anruf hier funktioniert die else-Klausel execut und den Wert ergibt auf.

Ich weiß nicht, wie Ausbeute umgesetzt wird oder wie eine Faser des Ausführungskontext verfolgt. Ich habe nicht in diesem Code aussehen. Fast alle der Enumerator und Faser Magie ist in C implementiert.

Sind Sie fragen wirklich, wie Fasern und Ausbeute umgesetzt werden? Welche Details suchen Sie?

Wenn ich weg von der Unterseite bin mir bitte korrigieren.

Wie die anderen Plakate erwähnt, ich glaube, es über eine eigene „Faser“ schafft [1.9]. In 1.8.7 (oder 1.8.6, wenn Sie das updates Juwel verwenden) irgendwie oder andere es tut die gleiche Sache (vielleicht, weil alle Fäden in 1,8 die äquivalent von Fasern sind, verwendet er sich nur?)

So in 1.9 und 1.8.x, wenn Sie von ihnen mehr Ketten zusammen a.each_line.map.each_with_index {}

Es fließt tatsächlich durch diese ganze Kette mit jeder Zeile, wie ein Art von Rohr auf der Befehlszeile

http://pragdave.blogs.pragprog.com /pragdave/2007/12/pipelines-using.html

HTH.

ich denke, das wäre genauer. jeweils auf der enumerator Aufruf sollte die gleiche sein wie die ursprüngliche Iteratormethode aufrufen. So würde ich leicht die ursprüngliche Lösung dieses Problems ändern:

class MyEnumerator
  include Enumerable

   def initialize(obj, iterator_method)
    @f = Fiber.new do
      @result = obj.send(iterator_method) do |*args|
       Fiber.yield(*args)
      end
      raise StopIteration
    end
   end

   def next(result)
     @f.resume result
   end

   def each
     result = nil
     loop do
      result = yield(self.next(result))
     end
     @result
   end
end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top