class_eval
&除instance_eval
以外的def
工作?内部class_eval
块def
定义类本身的方法(即实例方法),内部instance_eval
def
定义类的本征类的方法(即类方法)。 AFAIK所有其他功能在两种情况下都相同(例如define_method
,attr_accessor
,class << self; end
,定义常量)。这是真的吗?
答案:def
,undef
和alias
针对class_eval
和instance_eval
设置了不同的上下文。
答案 0 :(得分:13)
长话短说:
(object = Object.new).instance_eval &block
设置:
self
至object
object.singleton_class
Object.class_eval &block
设置:
self
至Object
Object
“当前类”用于def
,undef
和alias
,以及常量和类变量查找。
现在,我们来看看实现细节。
以下是在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 *argv, VALUE self) {
VALUE klass;
if (SPECIAL_CONST_P(self)) { klass = Qnil; }
else { klass = rb_singleton_class(self); }
return specific_eval(argc, argv, 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 values
。
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
yield_under
中有两个重要的行:
block.self = self;
这会将块的self
设置为接收者。
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
cref
是链接列表
它指定了“当前类”,用于def
,undef
和alias
作为常量和类变量查找。
该行基本上将cref
设置为under
。
最后:
从module_eval
致电时,under
将是Class
或Module
实例
从instance_eval
调用时,under
将是单身类
self
。
答案 1 :(得分:0)
instance_eval
允许您直接访问实例的实例变量,并使用self
作为实例的引用。