class_eval和amp;有什么区别吗? instance_eval工作除了def?在class_eval块内部,def定义了类本身的方法(即实例方法),而在instance_eval中,def定义了类的本征类的方法(即类方法). AFAIK所有其他功能在两种情况下都相同(例如,define_method,attr_accessor,class<< self; end,define constants).这是真的吗? 答案是:def,undef和别名对class_eval和instance_eval有不同的上下文.
解决方法
长话短说:
>(object = Object.new).instance_eval& block sets:
>自我反对
>“当前班级”到object.singleton_class
> Object.class_eval& block sets:
>自我对象
>对象的“当前类”
“当前类”用于def,undef和别名,以及常量和类变量查找.
现在,我们来看看实现细节.
以下是在C中实现module_eval
和instance_eval
的方式:
VALUE rb_mod_module_eval(int argc,VALUE *argv,VALUE mod) { return specific_eval(argc,argv,mod,mod); } VALUE rb_obj_instance_eval(int argc,VALUE self) { VALUE klass; if (SPECIAL_CONST_P(self)) { klass = Qnil; } else { klass = rb_singleton_class(self); } return specific_eval(argc,klass,self); }
两者都调用specific_eval
,它接受以下参数:int argc,VALUE * argv,VALUE klass和VALUE self.
注意:
> module_eval将Module或Class实例作为klass和self传递
> instance_eval将对象的单例类作为klass传递
如果给定一个块,则specific_eval将调用yield_under
,其中包含以下参数:VALUE under,VALUE self和VALUE值.
if (rb_block_given_p()) { rb_check_arity(argc,0); return yield_under(klass,self,Qundef); }
yield_under中有两个重要的行:
> block.self = self;
这将块的自身设置为接收器.
> cref = vm_cref_push(th,under,NOEX_PUBLIC,blockptr);
cref
是一个链表
它指定了“当前类”,用于def,undef和别名
作为常量和类变量查找.
该线基本上将cref设置为低于.
最后:
>从module_eval调用时,下面将是Class或Module实例.>从instance_eval调用时,下面将是单例类自.