Ruby 类评估与实例评估
除了Ruby 类评估与实例评估,ruby,metaprogramming,instance-eval,class-eval,Ruby,Metaprogramming,Instance Eval,Class Eval,除了def之外,class\u eval和instance\u eval的工作方式有什么不同吗?内部class_-evalblockdef定义了类自身的方法(即实例方法),内部instance_-eval定义了类的特征类的方法(即类方法)。AFAIK所有其他功能在这两种情况下都工作相同(例如,define_method,attr_accessor,classinstance_eval允许您直接访问实例的实例变量,并使用self作为实例的引用。长话短说: Object.instance\u ev
def
之外,class\u eval
和instance\u eval
的工作方式有什么不同吗?内部class_-eval
blockdef
定义了类自身的方法(即实例方法),内部instance_-eval
定义了类的特征类的方法(即类方法)。AFAIK所有其他功能在这两种情况下都工作相同(例如,define_method
,attr_accessor
,classinstance_eval
允许您直接访问实例的实例变量,并使用self
作为实例的引用。长话短说:
Object.instance\u eval&block
设置:
self
toObject
- 要创建的“当前类”
Object.class\u eval&block
设置:
self
toObject
- 将“当前类”添加到
对象
“当前类”用于def
、unde
和alias
,以及常量和类变量查找
现在,让我们看一下实现细节
以下是如何在C中实现和:
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);
}
这两个调用都采用以下参数:int argc
、VALUE*argv
、VALUE klass
和VALUE self
请注意:
module\u eval
将module
或Class
实例作为klass
和self
instance\u eval
将对象的单例类作为klass
如果给定一个块,specific\u eval
将调用,它将使用以下参数:下的值、值自身
和值值
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
在
下的yield\u中有两条重要的行:
block.self=self;
这将块的自身设置为接收器
cref=vm\u cref\u push(th,under,NOEX\u PUBLIC,blockptr);
这是一个链表
它指定了“当前类”,该类也用于def
、unde
和alias
作为常量和类变量查找
该行基本上将cref
设置为下的
最后:
- 从
module\u eval
调用时,
下的将是类
或模块
例如
从instance\u eval
调用时,
下的将是
self
class\u eval
和instance\u eval
在这方面的工作原理相同有一件事:在class\u eval
内部分配常量和类变量的工作方式与在类定义/重新打开中的工作方式不同:它使用外部作用域。@Alexey,你是对的。我打赌这与NODE\u FL\u CREF\u有关_按_EVAL
常量。例如,如果设置了标志,许多方法似乎会忽略cref
节点。第一个版本不应该是Object.class\u EVAL&block
?否则,您不会显示类上的实例_EVAL
和类上的类_EVAL
之间的差异,而是显示了差异在类的实例上的instance eval
和类上的class\u eval
之间。@MichaelHewson,我为class\u eval
使用了一个类,因为该方法仅为Module
实例定义。类是对象,因此instance\u eval
的行为类似,即使object=object
>self
将是对象
,但块中定义的方法将成为对象
的类方法,因为它们实际上是在对象上定义的。singleton_class
@Michael,我现在明白你的意思了,我同意。我将编辑我的答案以反映这一点。