使用代码块创建的枚举器实际如何运行
这只是一个简单的问题,y.<<
方法如何能够停止代码块的中间执行?
我预计代码块只运行一次并且永远不会在中间停止:/
e = Enumerator.new do |y|
puts "Ruby"
y << 1
y << 2
puts "Ruby"
y << 3
end
puts e.each.next
puts e.each.next
puts e.each.next
e.rewind
puts e.each.next
puts e.each.next
puts e.each.next
It's just a simple question, how is y.<<
method is able to halt the code-block mid execution ??
I have expected the code block to run only once and never halt in the middle :/
e = Enumerator.new do |y|
puts "Ruby"
y << 1
y << 2
puts "Ruby"
y << 3
end
puts e.each.next
puts e.each.next
puts e.each.next
e.rewind
puts e.each.next
puts e.each.next
puts e.each.next
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
几乎所有 Ruby 实现都是免费软件和开源的,因此您只需查看源代码即可了解它是如何实现的。
在 Rubinius 中,最有趣的部分是
Enumerator::Iterator#reset
,实现于 < a href="https://github.com/rubinius/rubinius/blob/master/core/enumerator.rb#L491-L498" rel="nofollow noreferrer">core/enumerator.rb
:和
Enumerator::Iterator#next
:TruffleRuby 的实现非常相似,您可以在
src/main/ruby/truffleruby/core/enumerator.rb
:JRuby 也非常相似,正如您在
核心/src/main/ruby/jruby/kernel/enumerator.rb
:MRuby 的实现非常相似,您可以在
mrbgems/mruby-enumerator/mrblib/enumerator.rb
。YARV 也使用 Fiber,如
enumerator.c
,例如这里:所以,毫不奇怪,
Enumerator
是使用 许多 Ruby 实现中的Fiber
。Fiber
本质上只是 Ruby 的半协程的名称,当然,协程是实现 生成器和迭代器。例如,CPython 和 CoreCLR 也使用协程实现生成器。一个例外似乎是 Opal。我的假设是 Opal 将使用 ECMAScript 生成器实现 Ruby
Enumerator
,但看起来情况并非如此。 Opal 中 RubyEnumerator
的实现可在opal/corelib/enumerator.rb
,opal/corelib/enumerator/generator.rb
和
opal/corelib/enumerator/yielder.rb
在opal/corelib/runtime.js
,但不幸的是,我并不完全理解它。不过,它似乎没有使用 RubyFiber
或 ECMAScript 生成器。顺便说一句,您对
Enumerator
的使用有点奇怪:您调用Enumerator#each
六次(不带块),但调用Enumerator#each
不带块只会返回Enumerator本身:
因此,换句话说,所有对
Enumerator#each
的调用都只是无操作。调用Enumerator#next< 会更有意义/code>
直接:
Almost all Ruby implementations are Free Software and Open Source, so you can just look at the source code to see how it is implemented.
In Rubinius, the most interesting part is
Enumerator::Iterator#reset
, implemented incore/enumerator.rb
:and
Enumerator::Iterator#next
:TruffleRuby's implementation is very similar, as you can see in
src/main/ruby/truffleruby/core/enumerator.rb
:JRuby is also very similar, as you can see in
core/src/main/ruby/jruby/kernel/enumerator.rb
:MRuby's implementation is very similar, as you can see in
mrbgems/mruby-enumerator/mrblib/enumerator.rb
.YARV also uses Fibers, as can be seen in
enumerator.c
, for example here:So, not surprisingly,
Enumerator
is implemented usingFiber
s in many Ruby implementations.Fiber
is essentially just Ruby's name for semi-coroutines, and of course, coroutines are a popular way of implementing generators and iterators. E.g. CPython and CoreCLR also implement generators using coroutines.One exception to this seems to be Opal. My assumption was that Opal would use ECMAScript Generators to implement Ruby
Enumerator
s, but it does not look like that is the case. The implementation of RubyEnumerator
s in Opal is found inopal/corelib/enumerator.rb
,opal/corelib/enumerator/generator.rb
, andopal/corelib/enumerator/yielder.rb
with some help fromopal/corelib/runtime.js
, but unfortunately, I don't fully understand it. It does not appear to use either RubyFiber
s or ECMAScript Generators, though.By the way, your usage of
Enumerator
s is somewhat strange: you callEnumerator#each
six times without a block, but callingEnumerator#each
without a block just returns theEnumerator
itself:So, in other words, all those calls to
Enumerator#each
are just no-ops. It would make much more sense to just callEnumerator#next
directly: