除了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有不同的上下文。
发布于 2012-04-24 21:11:22
长话短说:
Object.instance_eval &block集:self到ObjectObject.singleton_class
Object.class_eval &block集:self到ObjectObject
“当前类”用于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和selfinstance_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;这将将块的receiver.
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);设置为self。cref是一个链接列表,它指定用于def、undef和alias以及常量和类变量查找的“当前类”。
这一行基本上将cref设置为under。
最后:
- When called from `module_eval`, `under` will be the `Class` or `Module` instance.
- When called from `instance_eval`, `under` will be the _singleton class_ of `self`.
发布于 2012-04-24 18:23:22
instance_eval允许您直接访问实例的实例变量,并将self用作对实例的引用。
https://stackoverflow.com/questions/10302138
复制相似问题