Ruby: как работает этот блок через instance_eval? - PullRequest
2 голосов
/ 02 августа 2010

Я недавно видел какой-то код, который мне не совсем понятен.Существует массив с именем foo, который содержит экземпляры Proc объектов.Затем объект env используется для настройки среды для работы:

env = Object.new
foo.each do |f|
    env.instance_eval &f # what happens here?
end

Что именно происходит, когда вы открываете объект с instance_eval и передаете &f в качестве аргумента?Что происходит с env на этом этапе и с самим процессором?

Ответы [ 2 ]

2 голосов
/ 02 августа 2010

Область действия изменена для процедуры, которая затем оценивается в этом контексте. Внутри все процессы хранятся в памяти как C struct, который включает self процедуры (область, в которой был сделан процесс) Когда вы вызываете instance_eval, значение self вручную изменяется в памяти на объект, для которого вы вызываете instance_eval. Если вы изучите исходный код ruby, вы обнаружите, что он сводится к этой функции:

static VALUE
yield_under(VALUE under, VALUE self, VALUE values)
{
    rb_thread_t *th = GET_THREAD();
    rb_block_t block, *blockptr;
    NODE *cref;

    if ((blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0])) != 0) {
    block = *blockptr;
    block.self = self; // <- This is where the scope changes!
    th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
    }
    cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
    cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;

    if (values == Qundef) {
    return vm_yield_with_cref(th, 1, &self, cref);
    }
    else {
    return vm_yield_with_cref(th, RARRAY_LENINT(values), RARRAY_PTR(values), cref);
    }
}

Обратите внимание на строку, содержащую // <- This is where the scope changes!.

1 голос
/ 02 августа 2010

Proc выполняется в контексте env.Это как если бы вы вызывали метод на env: блок имеет доступ к своим переменным экземпляра, а также к открытым и закрытым методам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...