Ruby on rails Ruby:如何通过instance_eval运行这个块?
我最近看到了一些我不完全理解的代码。有一个名为Ruby on rails Ruby:如何通过instance_eval运行这个块?,ruby-on-rails,ruby,Ruby On Rails,Ruby,我最近看到了一些我不完全理解的代码。有一个名为foo的数组,其中包含Proc对象的实例。然后,使用环境对象设置要在其中工作的环境: env = Object.new foo.each do |f| env.instance_eval &f # what happens here? end 使用instance_eval打开对象并将&f作为参数传递时,会发生什么情况?此时env和Proc本身会发生什么情况?Proc的作用域会更改,然后在该上下文中对其进行评估。在内部,所有proc
foo
的数组,其中包含Proc
对象的实例。然后,使用环境对象设置要在其中工作的环境:
env = Object.new
foo.each do |f|
env.instance_eval &f # what happens here?
end
使用instance_eval打开对象并将
&f
作为参数传递时,会发生什么情况?此时env和Proc本身会发生什么情况?Proc的作用域会更改,然后在该上下文中对其进行评估。在内部,所有proc都以Cstruct
的形式存储在内存中,其中包括proc的self
(生成proc的范围)。调用instance\u eval
时,会在内存中将self
值手动更改为正在调用instance\u 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);
}
}
静态值
收益率(低于价值、自身价值、价值)
{
rb_thread_t*th=GET_thread();
rb_block_t block,*blockptr;
节点*cref;
如果((blockptr=GC_-GUARDED_-PTR_-REF(th->cfp->lfp[0]))!=0){
block=*blockptr;
block.self=self;//cfp->lfp[0]=GC\u-GUARDED\u-PTR(&block);
}
cref=vm_cref_push(th,under,NOEX_PUBLIC,blockptr);
cref->flags |=节点_FL _cref _由_EVAL推送_;
如果(值==Qundef){
返回带有cref(th,1和self,cref)的vm\u yield\u;
}
否则{
返回vm_yield_和cref(th,RARRAY_lent(值),RARRAY_PTR(值),cref);
}
}
注意,包含
/的行在env
的上下文中执行Proc。这就好像您在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"
env=Object.new
env.instance_variable_set:@test,“test”
“测试”类
env.instance_eval{test}#=>“test”