2010-08-02 60 views
2

我最近看到一些我不完全理解的代碼。有一個名爲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本身會發生什麼?

回答

1

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" 
2

範圍爲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); 
    } 
} 

注意就行了。