我对 Ruby 如何处理枚举器的创建有点困惑。基于块的迭代很有意义并且对我有用;我仍然很困惑 Enumerator 的返回应该如何以代码方式运行。
这是我正在使用的代码:
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
VALUE* args,
VALUE rb_self ) {
rb_thread_t* c_thread = GET_THREAD();
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
// c_top_of_control_frame describes the top edge of the stack trace
// set c_top_of_control_frame to the first frame in <main>
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
// for each control frame:
while ( c_current_context_frame < c_top_of_control_frame ) {
VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
// if we don't have a block, return enumerator
RETURN_ENUMERATOR( rb_self, 0, NULL );
// otherwise, yield the block
rb_yield( rb_frame_hash );
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
}
return Qnil;
}
在枚举器的情况下,如何调用 while 循环中的最后一行?
我的所有循环活动是否必须在调用 RETURN_ENUMERATOR 之前发生(因为 RETURN_ENUMERATOR 可能必须在 rb_yield() 之前)?
如果我想在内部迭代完成后发生一些事情怎么办?有了这个块,我可以简单地将它放在 while 循环之后;大概在枚举器的情况下同样有效 - 但如何?似乎每次通过循环它都会返回一个枚举器,那么枚举器是如何知道返回适当的对应对象的呢?rb_yield 将 rb_frame_hash 作为传递的 arg,但 RETURN_ENUMERATOR 似乎采用了在 Enumerator 在内部调用该方法时传递给该方法的 args。很明显,枚举器正在调用该方法本身——也许使用某种内部块来简单地返回 rb_frame_hash 的实例?
任何对内部结构的洞察力都值得赞赏。
-阿舍