class MyString
include Enumerable
def initialize(n)
@num = n
end
def each
i = 0
while i < @num
yield "#{i} within while"
puts "After yield #{i}"
i += 1
end
end
end
s = MyString.new(10)
a = s.to_enum
puts "first"
puts a.next
puts "second"
puts a.next
我的ruby版本是2.2.5,代码输出是
第一
之内
在...内0 第二
收益率0后 在
我认为执行流程为first a.next->s.each->while->yield->second a.next->jump into while loop
我的问题是如何实现Enumerator#next方法?
我可能知道调用的块产量有中断,这导致yield->second a.next
;但是,我不明白第二个a.next如何跳回到while循环中。
答案 0 :(得分:4)
我不明白第二个a.next如何跳回到while循环中。
魔法。 Enumerator
的(和Fiber
)超级大国。
这两个类在Ruby 1.9中引入,并且有许多相似之处;特别是,它们允许您进行手动合作绿色线程。
让我们首先看一下纤维,因为它们更基本:
f = Fiber.new do
puts "A"
Fiber.yield 1
puts "B"
Fiber.yield 2
puts "C"
end
puts "First" # First
puts f.resume # A
# 1
puts "Second" # Second
puts f.resume # B
# 2
puts "End" # End
f.resume # C
f.resume # FiberError: dead fiber called
基本上,光纤就像一个线程,但只要它产生Fiber.yield
,它就会暂停,并在Fiber#resume
恢复时恢复。它在C中实现为 Ruby 的基本功能,因此作为Ruby的学生(而不是Ruby interpreter 的学生),您不需要知道它是如何工作的,就像它一样(就像你需要知道IO#read
将读取一个文件,但不一定是如何在C中实现。)
Enumerator
几乎是相同的概念,但适用于迭代(而Fiber
更多用途)。实际上,我们可以用Enumerator
:
e = Enumerator.new do |yielder|
puts "A"
yielder.yield 1
puts "B"
yielder.yield 2
puts "C"
end
puts "First" # First
puts e.next # A
# 1
puts "Second" # Second
puts e.next # B
# 2
puts "End" # End
e.next # C
# StopIteration: iteration reached an end