系列文章原载于自己的博客,TOPI.CO (http://topi.co) ,某天不小心就 push 错啦,懒得从头再来,上传到 Ruby-China 来,一是方便自己回顾,另外也方便跟我一样的初学者
最近在看《Metaprogramming Ruby》的时候,看到代码块一章,在网上看到一篇介绍 instance_eval 与 class_eval 的文章:
###instance_eval
首先从名字可以得到的信息是,instance_eval的调用者 receiver 必须是一个实例 instance,而在 instance_eval block 的内部,self 即为 receiver 实例本身。
obj_instance.instance_eval do
self # => obj_instance
# current class => obj_instance's singleton class
end
根据这个定义,如果在一个实例上调用了 instance_eval,就可以在其中定义该实例的单态函数 singleton_method
class A
end
a = A.new
a.instance_eval do
self # => a
# current class => a's singleton class
def method1
puts 'this is a singleton method of instance a'
end
end
a.method1
#=> this is a singleton method of instance a
b = A.new
b.method1
#=>NoMethodError: undefined method `method1' for #<A:0x10043ff70>
同样,因为类 class 本身也是 Class 类的一个实例,instance_eval 也可以用在类上,这个时候就可以在其中定义该类的 singleton_method,即为该类的类函数。
换句话说,可以用 instance_eval 来定义类函数 class method,这比较容易混淆,需要搞清楚。
class A
end
A.instance_eval do
self # => A
# current class => A's singleton class
def method1
puts 'this is a singleton method of class A'
end
end
A.method1
#=> this is a singleton method of class A
class_eval
###class_eval
再来看class_eval,首先从名字可以得到的信息是,class_eval 的调用者 receiver 必须是一个类,而在 class_eval block 的内部,self 即为 receiver 类本身。
class A
end
A.class_eval do
self # => A
# current class => A
end
根据这个定义,如果在一个类上调用了 class_eval,就可以在其中定义该类的实例函数 instance_method
class A
end
a = A.new
a.method1
#=> NoMethodError: undefined method `method1' for #<A:0x10043ff70>
A.class_eval do
self # => A
# current class => A
def method1
puts 'this is a instance method of class A'
end
end
a.method1
#=> this is a instance method of class A
换句话说,可以用 class_eval 来定义实例函数 instance method,这也比较容易混淆,需要搞清楚。
###总结
instance_eval 必须由 instance 来调用,可以用来定义单态函数 singleton_methods
class_eval 必须是由 class 来调用,可以用来定义实例函数 instance_methods