简体   繁体   English

class_eval vs instance_eval

[英]class_eval vs instance_eval

Is there any difference in how class_eval & instance_eval work except def ? 除了def之外, class_evalinstance_eval工作方式有什么不同吗? Inside class_eval block def defines method to class itself (ie instance method) and inside instance_eval def defines method to the eigenclass of the class (ie class method). class_eval块内部, def定义了类本身的方法(即实例方法),而在instance_eval def定义了类的本征类的方法(即类方法)。 AFAIK all other features work identically in both cases (eg define_method , attr_accessor , class << self; end , defining constants). AFAIK所有其他功能在两种情况下都相同(例如define_methodattr_accessorclass << self; endattr_accessor constants)。 Is it true? 这是真的吗?

Answer is : def , undef and alias have different contexts for class_eval and instance_eval . 答案是defundefaliasclass_evalinstance_eval有不同的上下文。

Long story short: 长话短说:

  • Object.instance_eval &block sets: Object.instance_eval &block集:
  • Object.class_eval &block sets: Object.class_eval &block集:
    • self to Object self Object
    • The "current class" to Object Object的“当前类”

The "current class" is used for def , undef and alias , as well as constant and class variable lookups. “当前类”用于defundefalias ,以及常量和类变量查找。


Now, let's have a look at the implementation details. 现在,我们来看看实现细节。

Here's how module_eval and instance_eval are implemented in C: 以下是在C中实现module_evalinstance_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);
}

Both call specific_eval , which takes the following arguments: int argc , VALUE *argv , VALUE klass and VALUE self . 两者都调用specific_eval ,它采用以下参数: int argcVALUE *argvVALUE klassVALUE self

Note that: 注意:

  • module_eval passes the Module or Class instance as both klass and self module_evalModuleClass实例作为klass self传递
  • instance_eval passes the object's singleton class as klass instance_eval将对象的单例类作为klass传递

If given a block, specific_eval will call yield_under , which takes the following arguments: VALUE under , VALUE self and VALUE values . 如果给定一个块, specific_eval将调用yield_under ,它接受以下参数: VALUE underVALUE selfVALUE values

if (rb_block_given_p()) {
    rb_check_arity(argc, 0, 0);
    return yield_under(klass, self, Qundef);
}

There are two important lines in yield_under : yield_under有两个重要的行:

  1. block.self = self;

    This sets the self of the block to the receiver. 这将块的self设置为接收器。

  2. cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);

    The cref is a linked list which specifies the "current class", which is used for def , undef and alias , as well as constant and class variable lookups. cref是一个链接列表 ,它指定“当前类”,用于defundefalias ,以及常量和类变量查找。

    That line basically sets the cref to under . 该线基本上将cref设置为under

    Finally: 最后:

    • When called from module_eval , under will be the Class or Module instance. module_eval调用时, under将是ClassModule实例。

    • When called from instance_eval , under will be the singleton class of self . instance_eval调用时, under将是self单例类

instance_eval允许您直接访问实例的实例变量,并使用self作为实例的引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM