繁体   English   中英

class_eval vs instance_eval

[英]class_eval vs instance_eval

除了def之外, class_evalinstance_eval工作方式有什么不同吗? class_eval块内部, def定义了类本身的方法(即实例方法),而在instance_eval def定义了类的本征类的方法(即类方法)。 AFAIK所有其他功能在两种情况下都相同(例如define_methodattr_accessorclass << self; endattr_accessor constants)。 这是真的吗?

答案是defundefaliasclass_evalinstance_eval有不同的上下文。

长话短说:

  • Object.instance_eval &block集:
  • Object.class_eval &block集:
    • self Object
    • Object的“当前类”

“当前类”用于defundefalias ,以及常量和类变量查找。


现在,我们来看看实现细节。

以下是在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);
}

两者都调用specific_eval ,它采用以下参数: int argcVALUE *argvVALUE klassVALUE self

注意:

  • module_evalModuleClass实例作为klass self传递
  • instance_eval将对象的单例类作为klass传递

如果给定一个块, 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);
}

yield_under有两个重要的行:

  1. block.self = self;

    这将块的self设置为接收器。

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

    cref是一个链接列表 ,它指定“当前类”,用于defundefalias ,以及常量和类变量查找。

    该线基本上将cref设置为under

    最后:

    • module_eval调用时, under将是ClassModule实例。

    • instance_eval调用时, under将是self单例类

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

暂无
暂无

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

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