【Ruby】Enumeratorクラス その3。外部イテレータ、Fiber、yield
hp12cさんのブログの内容がすぐに理解できなかったので、手元で確認したよ。
http://melborne.github.io/2013/10/08/answer-to-is-this-a-bug-of-ruby-or-me/
外部イテレーターもFiberも理解したはずなのにぜんぜん分からない・・・!
ショック!
ちゃんと見直してみる。
内部クラスのインスタンス変数
本題とは関係ないけど、知らないとコードが追えなかったので。
インスタンス変数は、定義した最も内側のクラスだけが有効範囲となる。
class A class B def initialize @hoge=1 p "B dayo #{@hoge}" end end class C def initialize B.new p "C dayo #{@hoge}" end end end A::C.new
■実行結果
"B dayo 1" "C dayo "
Fiber.yieldの引数は@fiber.resumeの戻り値になる
Fiberの基本。
def reset @fiber = Fiber.new do @obj.each { |e| Fiber.yield(e*10) ;p "#{e} dayo"} end end def next @fiber.resume end p odd.next p odd.next
■実行結果
10 "1 dayo" 30
Fiber.yieldによって制御が移るため、
2回目のpメソッドは実行されない。
resetメソッドの読み方
def reset @fiber = Fiber.new do @obj.each { |e| Fiber.yield(e*10) ;p "#{e} dayo"} raise StopIteration, "iteration has ended" end end
resetメソッドではFiber.newしているのがポイント。
@obj.eachが実行されることによって、
変数currentの値がinitでリセットされる
nextメソッドは、eachをぐるぐる回しているわけではなく、
loopの中をぐるぐるしているだけ。
こんな風にpメソッドを入れれば理解できる。
class Generator def initialize(&blk1) @proc2 = blk1 #<= Enu.new do |y|の所のブロックが渡っている end def each(&blk2) #<= { |e| Fiber.yield(e*10) ;p "#{e} dayo"} が渡っている p "gygy" @proc2[Yielder.new(&blk2)] # y = Yielder.new(&blk2) end end odd = step(1, 2) p odd.next p odd.next odd.rewind p odd.next
initializeメソッドとeachメソッドの引数名が同じ事に惑わされたので、
変数名を&blk1と&blk2に変更してしまいました。
■実行結果
"gygy" 10 "1 dayo" 30 "3 dayo" 50 "gygy" 10
学んだこと
Fiberには手を出さない。