對于instance_eval和class_eval绽乔,在看ruby元編程時以為搞清楚了补疑,但最近發(fā)現(xiàn)一種情況歧沪,卻又讓我迷糊了:
class_eval
class A
end
A.class_eval
def a
puts 'a'
end
define_method :b do
puts 'b'
end
end
A.new.a # 'a'
A.new.b # 'b'
#a和b都是A的實(shí)例方法
instance_eval
class A
end
A.instance_eval do
def a
puts 'a'
end
define_method :b do
puts 'b'
end
end
A.new.b # 'b' b為實(shí)例方法
A.new.a # no method error!!!
A.a # ‘a(chǎn)’
為什么在instance_eval中 def 和define_method定義的一個為類方法(類的單件方法) 一個為實(shí)例方法呢?
要解釋這個問題莲组,首先要有以下概念:
ruby在執(zhí)行時诊胞,會一直追蹤當(dāng)前對象(receiver)即self,但也會追蹤當(dāng)前類(current class)锹杈。instance_eval和class_eval都會修改self和current class:
- klass.class_eval 修改self為klass撵孤,修改current class為klass
- obj.instance_eval 修改self為obj,修改current class為
obj的eigen_class(singleton_class)。
了解了以上知識竭望,我們知道define_method的接受者為self,class_eval和instance_eval都改變self為調(diào)用者本身邪码,所以定義的為實(shí)例方法;而對def起作用的是當(dāng)前類(current class)咬清,class_eval修改當(dāng)前類為調(diào)用者本身闭专,所以定義的是實(shí)例方法,而instance_eval修改當(dāng)前類為調(diào)用者的eigen_class(singleton_class)旧烧,所以定義的是類方法(類的單件方法)影钉。
另外,class_eval僅類可調(diào)用粪滤,instance_eval則類和對象都可調(diào)用斧拍。
class(instance)_exec與eval基本相似,但有以下不同:
- _eval 既可傳遞字符串杖小,也可傳遞塊肆汹,如123.instance_eval 'to_s'
- _exec只能傳遞快、不能傳字符串予权,但_exec可以為block傳遞參數(shù)如 Class.instance_exec('Self'){|x|p "#{x}:self"}
至此昂勉,class_eval,instance_eval,instance_exec,instance_eval概念基本都透徹了扫腺。
對于current class有些未說清的(未研究透徹,初步判斷current class 對關(guān)鍵字起作用岗照,self對方法調(diào)用起作用~),回頭研究完單寫一篇。
轉(zhuǎn)載請注明出處: http://me.angry-arthas.com/blog/2015/06/07/instance-ev-instance-exec-class-eval-class-exec-qu-bie/