我最近看到一些我不完全理解的代碼。有一個名爲foo
的數組,其中包含Proc
對象的實例。然後,ENV對象用於設置的環境中工作:Ruby:如何通過instance_eval運行此塊?
env = Object.new
foo.each do |f|
env.instance_eval &f # what happens here?
end
當您打開的對象與instance_eval的,並通過&f
作爲參數,到底會發生什麼? env在這一點和Proc本身會發生什麼?
我最近看到一些我不完全理解的代碼。有一個名爲foo
的數組,其中包含Proc
對象的實例。然後,ENV對象用於設置的環境中工作:Ruby:如何通過instance_eval運行此塊?
env = Object.new
foo.each do |f|
env.instance_eval &f # what happens here?
end
當您打開的對象與instance_eval的,並通過&f
作爲參數,到底會發生什麼? env在這一點和Proc本身會發生什麼?
Proc在env
的上下文中執行。就好像您正在調用env
上的方法:該塊可以訪問其實例變量以及公共和私有方法。
env = Object.new
env.instance_variable_set :@test, "test"
class << env
private
def test
@test
end
end
env.instance_eval { @test } #=> "test"
env.instance_eval { test } #=> "test"
範圍爲proc更改,然後在該上下文中進行評估。在內部,所有過程都作爲C struct
存儲在內存中,其中包括過程的self
(過程的作用域)。當您撥打instance_eval
時,self
值將在內存中手動更改爲您要撥打instance_eval
的對象。如果您探索紅寶石源代碼,你會發現它歸結爲這樣的功能:含// <- This is where the scope changes!
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);
}
}
注意就行了。