Рубиновая перечисление и return_enumerator - Вопросы относительно внутренних внутренних интервалов Ruby C

StackOverflow https://stackoverflow.com/questions/3193214

  •  02-10-2019
  •  | 
  •  

Вопрос

Я немного смущен тем, как Руби справляется с созданием перечислений. Итерация на основе блоков имеет смысл и работает для меня; Я все еще запутался, как предполагается возвращение перечислителя по коду.

Вот код, с которым я работаю:

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;
}

Как будет вызвана окончательная строка в цикле Whis в случае перечисления?

Должен ли все мои циклы с циклом проходить до вызовов в return_enumerator (поскольку return_enumerator, по -видимому, должен быть до rb_yield ())?

Что, если я хочу, чтобы что -то произошло, как только внутренняя итерация заканчивается? С блоком я могу просто положить его после петли Whit; Предположительно одинаковые работы в случае перечисления- но как? Кажется, что каждый раз через цикл он возвращает перечислитель, так как же перечислитель узнает, чтобы вернуть соответствующий соответствующий объект? RB_YIELD получает RB_FRAME_HASH в качестве пропущенного ARG, но return_enumerator, похоже, принимает ARG, которые передаются на метод, когда перечисление вызывает метод внутри. Таким образом, ясно, что перечисление вызывает сам метод- возможно, с каким-то внутренним блоком, который просто возвращает экземпляр RB_FRAME_HASH?

Любое понимание внутренних участников ценится.

-Эшер

Это было полезно?

Решение

Чтобы попытаться ответить на мой собственный вопрос:

Когда называется return_enumerator, называется rb_enumeratorize, который создает перечислитель. Перечисление возвращается; Когда: Далее вызывает перечисление, инициализируется (если необходимо (при необходимости волокно) или возобновляется. Каждый раз: следующее называется, оптоволокно отражает внутренне предоставленный блок один раз, чтобы получить следующий элемент итератора (настройка no_next в структуре C и вызова RB_FIBER_YIELD на волокно перечислителя).

Таким образом, может показаться, что деятельность по петле не должна иметь место до return_enumerator. Я еще не ясно в действиях после перечисления в функции, возвращающем перечисление в случае, когда блок не был предоставлен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top