ruby的class << self, 及其class_eval和instance_eval的区别
2014-04-27 18:15
447 查看
转自:http://blog.csdn.net/lyx2007825/article/details/10089115
单态方法——singleton_method
关于class << self,有一篇比较好的博文,请见:http://www.devalot.com/articles/2008/09/ruby-singleton
定义singleton_methods有三种方式
第一种: 直接给对象打开定义
这是最简单相信也是见得最多的一种方式:
[ruby] view
plaincopy
a = Array.new
def a.size
"Hello World!"
end
输入puts a.size ====>输出"Hello,World",而不是0
我们知道ruby比较有特点的一个地方是,在任何时间任何地点,可以对一个类或对象打开进行添加方法或者重写方法。
但这是为什么呢?不知道读者有没有想过这个问题。从静态语言的角度,比如java或者C++,我么知道只能在一个类的范围内添加方法。学过汇编的朋友知道,方法本身是内存中的一段指令而已。只不过把一些传参或者返回之放在指定的寄存器上。而ruby底层是用C写的。C++和java中的类本质跟C中的结构体也没有什么区别,术语多态和回调只不过是在指定的方法表(每个java类字节码都有一个方法表)入口处放置实际C的函数指针。
经过上面的分析,是不是意味着ruby类的开放性也是基于类的呢?
查过google之后,发觉分析对了。原来ruby在任何地方能对一个既存的对象打开也是基于类的,只不过是个匿名的内部类而已,而这个类继承于当前实例的类。
所以,在上面的代码中,我们完全可以调用super方法调用父类的相应函数。如
[ruby] view
plaincopy
a = Array.new
def a.size
puts super
"Hello World!"
end
puts a.size ======> 输出
0
"Hello,World"
说明我们理解没有偏差。
这样,我们对于第二种方式也就不难理解了。
第二种:使用"<<"方式
上面的代码还可以这样写:
[ruby] view
plaincopy
a = Array.new
class << a
def size
puts super
"Hello,World"
end
end
puts a.size =======>
0
"Hello,World"
b = Array.new
puts b.size =========>
0
很显然,第二种方式比较能体现本质(某一个类继承于a,然后重写size这个方法)
第三种方式,通过instance_eval
[ruby] view
plaincopy
a = Array.new
a.instance_eval <<EOF
def size
puts super
puts "Hello,World!"
end
EOF
<strong>b = Array.new
a.size =======>
0
"Hello,World"
b.size ====>
0</strong>
虽然明白instance_eval是singleton_method方式的一种,但是因为是第一次见instance_eval,于是google之,发现原来这玩意儿和class_eval很相似。于是又google class_eval.
于是,又发现一篇比较好的博文:http://www.jimmycuadra.com/posts/metaprogramming-ruby-class-eval-and-instance-eval
博文中说道,class_module是从Module中得到的,所以class_module的接受者必须是个类,比如说
[ruby] view
plaincopy
a=Array.new
a.class_eval 这样是错的,会报找不到class_eval这个方法
应该是Array.class_eval才可以
而我们知道在混合编程(mix)中,include 某个Module时,该Module的所有实例方法只能由子类的实例所调用(相当于多了继承于Module),故class_eval定义之后,只能是Array的所有的实例调用,Array自己调用会出错(肯定的,假如Array自己调用不出错的话,这个方法就是静态方法了)
[ruby] view
plaincopy
a=Array.new
Array.class_eval do
def hint
"hello"
end
end
puts a,hint 输出hello
b = Array.new
puts b.hint 输出hello
puts A.hint 出错,没有找到这个方法
ruby是完全面向对象的,即使对于某个实际的类也是如此。ruby的任何类,比如Array,或者是任何自己定义的类,都是Class类的实例。所以,类的静态方法,相当于这个类(或者是Class类的对象)的singleton_methods.也就是说,ruby本质是没有静态方法的。
基于此,也就很自然的明白instance_eval了。
比如,我像下面这样定义
[ruby] view
plaincopy
a=Array.new
a.instance_eval do
def hint
"hello"
end
end
puts a.hint 输出hello
b=Array.new
puts b.hint 报错,没有找到此方法
假如我像下面这样定义:
Array.instance_eval do
def hint
"hello"
end
end
本质上相当于这样的代码:
class Array
def self.hint
"hello"
end
end
当然,也可以是这样
class Array
class << self
def hint
"hello"
end
end
end
<strong><span style="color:#660000;">不过ruby对静态代码的限制比较强,不像java,实例可以调用静态方法,在ruby中,静态方法只能是类调用,因为ruby本质是没有静态方法的,只有实例方法。只有所属的对象才能调用自己的
方法,这也间接地说明了ruby是一种完全的面向对象语言。</span></strong>
单态方法——singleton_method
关于class << self,有一篇比较好的博文,请见:http://www.devalot.com/articles/2008/09/ruby-singleton
定义singleton_methods有三种方式
第一种: 直接给对象打开定义
这是最简单相信也是见得最多的一种方式:
[ruby] view
plaincopy
a = Array.new
def a.size
"Hello World!"
end
输入puts a.size ====>输出"Hello,World",而不是0
我们知道ruby比较有特点的一个地方是,在任何时间任何地点,可以对一个类或对象打开进行添加方法或者重写方法。
但这是为什么呢?不知道读者有没有想过这个问题。从静态语言的角度,比如java或者C++,我么知道只能在一个类的范围内添加方法。学过汇编的朋友知道,方法本身是内存中的一段指令而已。只不过把一些传参或者返回之放在指定的寄存器上。而ruby底层是用C写的。C++和java中的类本质跟C中的结构体也没有什么区别,术语多态和回调只不过是在指定的方法表(每个java类字节码都有一个方法表)入口处放置实际C的函数指针。
经过上面的分析,是不是意味着ruby类的开放性也是基于类的呢?
查过google之后,发觉分析对了。原来ruby在任何地方能对一个既存的对象打开也是基于类的,只不过是个匿名的内部类而已,而这个类继承于当前实例的类。
所以,在上面的代码中,我们完全可以调用super方法调用父类的相应函数。如
[ruby] view
plaincopy
a = Array.new
def a.size
puts super
"Hello World!"
end
puts a.size ======> 输出
0
"Hello,World"
说明我们理解没有偏差。
这样,我们对于第二种方式也就不难理解了。
第二种:使用"<<"方式
上面的代码还可以这样写:
[ruby] view
plaincopy
a = Array.new
class << a
def size
puts super
"Hello,World"
end
end
puts a.size =======>
0
"Hello,World"
b = Array.new
puts b.size =========>
0
很显然,第二种方式比较能体现本质(某一个类继承于a,然后重写size这个方法)
第三种方式,通过instance_eval
[ruby] view
plaincopy
a = Array.new
a.instance_eval <<EOF
def size
puts super
puts "Hello,World!"
end
EOF
<strong>b = Array.new
a.size =======>
0
"Hello,World"
b.size ====>
0</strong>
虽然明白instance_eval是singleton_method方式的一种,但是因为是第一次见instance_eval,于是google之,发现原来这玩意儿和class_eval很相似。于是又google class_eval.
于是,又发现一篇比较好的博文:http://www.jimmycuadra.com/posts/metaprogramming-ruby-class-eval-and-instance-eval
博文中说道,class_module是从Module中得到的,所以class_module的接受者必须是个类,比如说
[ruby] view
plaincopy
a=Array.new
a.class_eval 这样是错的,会报找不到class_eval这个方法
应该是Array.class_eval才可以
而我们知道在混合编程(mix)中,include 某个Module时,该Module的所有实例方法只能由子类的实例所调用(相当于多了继承于Module),故class_eval定义之后,只能是Array的所有的实例调用,Array自己调用会出错(肯定的,假如Array自己调用不出错的话,这个方法就是静态方法了)
[ruby] view
plaincopy
a=Array.new
Array.class_eval do
def hint
"hello"
end
end
puts a,hint 输出hello
b = Array.new
puts b.hint 输出hello
puts A.hint 出错,没有找到这个方法
ruby是完全面向对象的,即使对于某个实际的类也是如此。ruby的任何类,比如Array,或者是任何自己定义的类,都是Class类的实例。所以,类的静态方法,相当于这个类(或者是Class类的对象)的singleton_methods.也就是说,ruby本质是没有静态方法的。
基于此,也就很自然的明白instance_eval了。
比如,我像下面这样定义
[ruby] view
plaincopy
a=Array.new
a.instance_eval do
def hint
"hello"
end
end
puts a.hint 输出hello
b=Array.new
puts b.hint 报错,没有找到此方法
假如我像下面这样定义:
Array.instance_eval do
def hint
"hello"
end
end
本质上相当于这样的代码:
class Array
def self.hint
"hello"
end
end
当然,也可以是这样
class Array
class << self
def hint
"hello"
end
end
end
<strong><span style="color:#660000;">不过ruby对静态代码的限制比较强,不像java,实例可以调用静态方法,在ruby中,静态方法只能是类调用,因为ruby本质是没有静态方法的,只有实例方法。只有所属的对象才能调用自己的
方法,这也间接地说明了ruby是一种完全的面向对象语言。</span></strong>
相关文章推荐
- ruby的class << self, 及其class_eval和instance_eval的区别
- ruby的class << self, 及其class_eval和instance_eval的区别
- ruby的instance_eval和class_eval, self && current class
- 详解Ruby中的instance_eval方法及其与class_eval的对比
- ruby中的instance_eval,class_eval,eval
- [Ruby] ruby创建类方法 ,以及class_eval 、instance_eval的使用
- Class<Object>与Class<?>有何区别呢
- #import、#include、@class、#import<> 、#import""的区别
- [Ruby笔记]23.Ruby self “main class module instance”
- iOS - @class ,#import" ",#import<>的区别
- 【Ruby】instance_eval和class_eval用法讲解
- Class<Object>与Class<?>有何区别
- 关于ASP中用Repeater数据填充,<%#Eval() %>和<%#Container.DataItem()%>等方法的区别
- rails环境下 ruby环境下class_eval的区别
- yield self和instance_eval用法区别
- class_eval 和 instance_eval的区别
- <%#eval%>和<%#bind%>的区别
- class_eval和instance_eval的区别
- Java中Class<T>与Class<?>之间有何区别
- instance_eval与class_eval的区别