這只是一個簡單的問題,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
uj5u.com熱心網友回復:
幾乎所有 Ruby 實作都是自由軟體和開源的,因此您只需查看源代碼即可了解它是如何實作的。
在Rubinius中,最有趣的部分是Enumerator::Iterator#reset,實作于core/enumerator.rb:
@fiber = Fiber.new stack_size: STACK_SIZE do
obj = @object
@result = obj.each { |*val| Fiber.yield *val }
@done = true
end
和Enumerator::Iterator#next:
val = @fiber.resume
TruffleRuby的實作非常相似,如下所示src/main/ruby/truffleruby/core/enumerator.rb:
class FiberGenerator
# irrelevant methods omitted
def next
reset unless @fiber
val = @fiber.resume
raise StopIteration, 'iteration has ended' if @done
val
end
def reset
@done = false
@fiber = Fiber.new do
obj = @object
@result = obj.each do |*val|
Fiber.yield(*val)
end
@done = true
end
end
end
JRuby也非常相似,您可以在以下代碼中看到core/src/main/ruby/jruby/kernel/enumerator.rb:
class FiberGenerator
# irrelevant methods omitted
def next
reset unless @fiber&.__alive__
val = @fiber.resume
raise StopIteration, 'iteration has ended' if @state.done
val
end
def reset
@state.done = false
@state.result = nil
@fiber = Fiber.new(&@state)
end
end
MRuby的實作非常相似,如您在mrbgems/mruby-enumerator/mrblib/enumerator.rb.
YARV也使用 Fibers,如 中所示enumerator.c,例如這里:
static void
next_init(VALUE obj, struct enumerator *e)
{
VALUE curr = rb_fiber_current();
e->dst = curr;
e->fib = rb_fiber_new(next_i, obj);
e->lookahead = Qundef;
}
static VALUE
get_next_values(VALUE obj, struct enumerator *e)
{
VALUE curr, vs;
if (e->stop_exc)
rb_exc_raise(e->stop_exc);
curr = rb_fiber_current();
if (!e->fib || !rb_fiber_alive_p(e->fib)) {
next_init(obj, e);
}
vs = rb_fiber_resume(e->fib, 1, &curr);
if (e->stop_exc) {
e->fib = 0;
e->dst = Qnil;
e->lookahead = Qundef;
e->feedvalue = Qundef;
rb_exc_raise(e->stop_exc);
}
return vs;
}
因此,毫不奇怪,在許多 Ruby 實作中Enumerator使用s 來實作。本質上只是 Ruby 對semi-coroutines的稱呼,當然,coroutines 是一種流行的實作生成器和迭代器的方式。例如,CPython 和 CoreCLR 也使用協程實作生成器。FiberFiber
One exception to this seems to be Opal. My assumption was that Opal would use ECMAScript Generators to implement Ruby Enumerators, but it does not look like that is the case. The implementation of Ruby Enumerators in Opal is found in opal/corelib/enumerator.rb, opal/corelib/enumerator/generator.rb, and opal/corelib/enumerator/yielder.rb with some help from opal/corelib/runtime.js, but unfortunately, I don't fully understand it. It does not appear to use either Ruby Fibers or ECMAScript Generators, though.
By the way, your usage of Enumerators is somewhat strange: you call Enumerator#each six times without a block, but calling Enumerator#each without a block just returns the Enumerator itself:
each→enumIterates over the block according to how this
Enumeratorwas constructed. If no block and no arguments are given, returns self.
So, in other words, all those calls to Enumerator#each are just no-ops. It would make much more sense to just call Enumerator#next directly:
puts e.next
puts e.next
puts e.next
e.rewind
puts e.next
puts e.next
puts e.next
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/434166.html
上一篇:用于銀行交易決議的正則運算式
