2010-07-07 54 views
0

我對Ruby如何處理創建枚舉器有點困惑。基於塊的迭代是有意義的,併爲我工作;我仍然對Enumerator的返回應該如何以代碼方式工作感到困惑。Ruby枚舉和RETURN_ENUMERATOR - 關於Ruby的C內部的問題

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如何知道返回適當的相應對象呢? rb_yield獲取rb_frame_hash作爲傳遞的參數,但是當Enumerator在內部調用方法時,RETURN_ENUMERATOR似乎採用了傳遞給方法的參數。很顯然,Enumerator正在調用這個方法本身 - 可能是通過某種內部塊來簡單地返回rb_frame_hash的實例?

對內部的任何深入瞭解。

-Asher

回答

0

要試圖回答我的問題:

當RETURN_ENUMERATOR被調用時,rb_enumeratorize被調用,它創建了一個枚舉。枚舉器返回;何時:在枚舉器上調用下一個,光纖被初始化(如果需要)或恢復。每次調用next時,Fiber會迭代一次內部提供的塊以獲取下一個迭代器項(在Enumerator的C結構中設置no_next,並在Enumerator的光纖上調用rb_fiber_yield)。

所以看起來循環活動不必在RETURN_ENUMERATOR之前發生。如果在沒有提供塊的情況下返回Enumerator的函數中的枚舉枚舉之後,我還不清楚。