0

我对 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 的实例?

任何对内部结构的洞察力都值得赞赏。

-阿舍

4

1 回答 1

0

尝试回答我自己的问题:

当 RETURN_ENUMERATOR 被调用时,rb_enumeratorize 被调用,它创建了一个 Enumerator。返回枚举器;当在枚举器上调用 :next 时,Fiber 被初始化(如果需要)或恢复。每次调用 :next 时,Fiber 都会迭代一次内部提供的块以获得下一个迭代器项(在 Enumerator 的 C 结构中设置 no_next 并在 Enumerator 的 Fiber 上调用 rb_fiber_yield)。

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

于 2010-07-08T08:56:37.260 回答