我对Ruby如何处理枚举器的创建感到有些困惑。基于块的迭代很有意义,对我有用;我仍然感到困惑的是,枚举器的返回应该如何以代码方式运行。
以下是我正在使用的代码:
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循环之后;大概在调查员的情况下也是如此 - 但是如何?似乎每次循环都会返回一个Enumerator,那么Enumerator如何知道返回相应的相应对象呢? rb_yield将rb_frame_hash作为传递的arg获取,但是当Enumerator在内部调用该方法时,RETURN_ENUMERATOR似乎采用中继到该方法的args。很明显,Enumerator正在调用方法本身 - 也许是某种内部块只是返回rb_frame_hash的实例?
对内部的任何见解都表示赞赏。
-Asher
答案 0 :(得分:0)
试图回答我自己的问题:
调用RETURN_ENUMERATOR时,将调用rb_enumeratorize,从而创建一个Enumerator。调查员被退回; when:在枚举器上调用next,光纤被初始化(如果需要)或恢复。每次:调用next,Fiber迭代内部提供的块一次,以获得下一个迭代器项(在Enumerator的C结构中设置no_next并在Enumerator的Fibre上调用rb_fiber_yield)。
所以看起来循环活动不必在RETURN_ENUMERATOR之前发生。在没有提供块的情况下返回枚举器的函数中枚举后我还没有清楚。