Ruby Enumeration和RETURN_ENUMERATOR - 关于Ruby的C内部的问题

时间:2010-07-07 08:44:55

标签: c ruby enumerator

我对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

1 个答案:

答案 0 :(得分:0)

试图回答我自己的问题:

调用RETURN_ENUMERATOR时,将调用rb_enumeratorize,从而创建一个Enumerator。调查员被退回; when:在枚举器上调用next,光纤被初始化(如果需要)或恢复。每次:调用next,Fiber迭代内部提供的块一次,以获得下一个迭代器项(在Enumerator的C结构中设置no_next并在Enumerator的Fibre上调用rb_fiber_yield)。

所以看起来循环活动不必在RETURN_ENUMERATOR之前发生。在没有提供块的情况下返回枚举器的函数中枚举后我还没有清楚。