8

class_eval除了 之外,工作方式和instance_eval工作方式有什么不同def吗?内部class_evaldef为类本身定义方法(即实例方法),内部块为类instance_eval def的特征类定义方法(即类方法)。AFAIK 所有其他功能在这两种情况下的工作方式相同(例如define_method, attr_accessor, class << self; end, 定义常量)。这是真的吗?

答案是defundef和有不同的alias上下文。class_evalinstance_eval

4

2 回答 2

16

长话短说:

  • Object.instance_eval &block套:
  • Object.class_eval &block套:
    • selfObject
    • “当前班级”到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 *argv和。VALUE klassVALUE self

注意:

  • module_evalModuleorClass实例作为两个klass and传递 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,以及常量和类变量查找。

    该行基本上将 设置crefunder

    最后:

    • 当从 调用时module_evalunder将是ClassorModule 实例。

    • 当从 调用时instance_evalunder将是 的单例self

于 2012-04-24T21:11:22.690 回答
0

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

于 2012-04-24T18:23:22.273 回答