[英]class_eval vs instance_eval
除了def
之外, class_eval
和instance_eval
工作方式有什么不同嗎? 在class_eval
塊內部, def
定義了類本身的方法(即實例方法),而在instance_eval
def
定義了類的本征類的方法(即類方法)。 AFAIK所有其他功能在兩種情況下都相同(例如define_method
, attr_accessor
, class << self; end
, attr_accessor
constants)。 這是真的嗎?
答案是 : def
, undef
和alias
對class_eval
和instance_eval
有不同的上下文。
長話短說:
Object.instance_eval &block
集:
self
Object
Object.singleton_class
的“當前類” Object.class_eval &block
集:
self
Object
Object
的“當前類” “當前類”用於def
, undef
和alias
,以及常量和類變量查找。
現在,我們來看看實現細節。
以下是在C中實現module_eval
和instance_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 argc
, VALUE *argv
, VALUE klass
和VALUE self
。
注意:
module_eval
將Module
或Class
實例作為klass
和 self
傳遞 instance_eval
將對象的單例類作為klass
傳遞 如果給定一個塊, specific_eval
將調用yield_under
,它接受以下參數: VALUE under
, VALUE self
和VALUE values
。
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
yield_under
有兩個重要的行:
block.self = self;
這將塊的self
設置為接收器。
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
cref
是一個鏈接列表 ,它指定“當前類”,用於def
, undef
和alias
,以及常量和類變量查找。
該線基本上將cref
設置為under
。
最后:
從module_eval
調用時, under
將是Class
或Module
實例。
從instance_eval
調用時, under
將是self
的單例類 。
instance_eval
允許您直接訪問實例的實例變量,並使用self
作為實例的引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.