Ruby Enumeration and Return_Enumerator- RubyのC内部に関する質問
-
02-10-2019 - |
質問
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ループの後に単純に配置できます。おそらく、列挙者の場合に同じ作品が同じですが、どうですか?ループを介して列挙者を返すたびに、列挙者は適切な対応するオブジェクトをどのように返すことを知っているように思われます。 rb_yieldはrb_frame_hashを渡されたargとして取得しますが、return_enumeratorは、列挙者がメソッドを内部的に呼び出すときにメソッドに中継されるargを取得するようです。したがって、列挙者は明らかにメソッド自体を呼び出しています。おそらく、rb_frame_hashのインスタンスを単に返すようなある種の内部ブロックを使用して?
内部についての洞察は高く評価されています。
-Asher
解決
自分の質問に答えようとする:
Return_Enumeratorが呼び出されると、RB_Enumeratorizeが呼び出され、列挙器が作成されます。列挙器が返されます。いつ:次に列挙されている場合は、繊維が初期化(必要に応じて)または再開されます。毎回:次は呼び出されます。ファイバーは、次のイテレーターアイテムを取得するために、内部で提供されたブロックを1回繰り返します(列挙者のc構造体にno_nextを設定し、列挙器のファイバーでrb_fiber_yieldを呼び出します)。
したがって、Return_Enumeratorの前にループアクティビティを行う必要はないようです。ブロックが提供されていない場合、列挙器を返す関数の列挙後のアクションについてはまだ明確ではありません。