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

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top