对于instance_eval和class_eval,在看ruby元编程时以为搞清楚了,但最近发现一种情况,却又让我迷糊了:
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的实例方法
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为实例方法
A.new.a # no method error!!!
A.a # ‘a’
为什么在instance_eval中 def 和define_method定义的一个为类方法(类的单件方法) 一个为实例方法呢?
要解释这个问题,首先要有以下概念:
ruby在执行时,会一直追踪当前对象(receiver)即self,但也会追踪当前类(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为调用者本身,所以定义的为实例方法;而对def起作用的是当前类(current class),class_eval修改当前类为调用者本身,所以定义的是实例方法,而instance_eval修改当前类为调用者的eigen_class(singleton_class),所以定义的是类方法(类的单件方法)。
另外,class_eval仅类可调用,instance_eval则类和对象都可调用。
class(instance)_exec与eval基本相似,但有以下不同:
- _eval 既可传递字符串,也可传递块,如123.instance_eval 'to_s'
- _exec只能传递快、不能传字符串,但_exec可以为block传递参数如 Class.instance_exec('Self'){|x|p "#{x}:self"}
至此,class_eval,instance_eval,instance_exec,instance_eval概念基本都透彻了。
对于current class有些未说清的(未研究透彻,初步判断current class 对关键字起作用,self对方法调用起作用~),回头研究完单写一篇。
转载请注明出处: http://me.angry-arthas.com/blog/2015/06/07/instance-ev-instance-exec-class-eval-class-exec-qu-bie/