Ruby Énumération et RETURN_ENUMERATOR - Questions concernant C Internes Ruby
-
02-10-2019 - |
Question
Je suis un peu confus sur la façon dont Ruby gère la création des recenseurs. itération par bloc est logique et travaille pour moi; Je suis toujours confus comment le retour d'un recenseur est censé code sage fonction.
Voici le code, je travaille avec:
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;
}
Comment la dernière ligne dans la boucle while appelée dans le cas d'un recenseur?
fait tout mon activité en boucle doivent avoir lieu avant que les appels à RETURN_ENUMERATOR (depuis RETURN_ENUMERATOR a sans doute à venir avant rb_yield ())?
Que faire si je veux quelque chose se produise une fois que les finitions d'itération interne? Avec le bloc, je peux tout simplement après la boucle while; sans doute les mêmes œuvres dans le cas d'un Enumerator- mais comment? Il semble que chaque fois à travers la boucle, il retourne un recenseur, alors comment le recenseur sait retourner l'objet correspondant de approprié? rb_yield obtient rb_frame_hash comme un arg passé, mais RETURN_ENUMERATOR semble prendre les args qui sont relayés à la méthode lorsque le recenseur appelle la méthode interne. Il apparaît donc clairement l'agent recenseur appelle la méthode itself- peut-être avec une sorte de bloc interne qui retourne simplement l'instance de rb_frame_hash?
Tout aperçu des internes est apprécié.
-Asher
La solution
Pour tenter de répondre à ma propre question:
Quand RETURN_ENUMERATOR est appelé, rb_enumeratorize est appelée, ce qui crée un recenseur. Le recenseur est retourné; lorsque: la prochaine est appelée sur le recenseur, une fibre est initialisé (si nécessaire) ou d'une reprise. Chaque fois que: la prochaine est appelée, la fibre itère un bloc fourni en interne une fois afin d'obtenir l'élément suivant iterator (réglage no_next dans le struct C du recenseur et appelant rb_fiber_yield sur les fibres du recenseur).
Il semblerait que l'activité de la boucle ne doit pas avoir lieu avant RETURN_ENUMERATOR. Je ne suis pas encore clair sur les actions après l'énumération en fonction renvoyant un recenseur dans le cas où un bloc n'a pas été fourni.