簡體   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