Ruby(二)There is only one kind of object

上一篇关于ruby的文章提到了ruby的七条金科玉律。本篇就讲解一下第一条。

There is only one kind of object—be it a regular object or a module.

什么意思呢?就是说ruby只有一种类型的对象,不论它是一个常规的对象,还是个module。言外之意是,常规对象和module在作为“对象”这一点上是无差别的,从这个意义上讲,module并没有它的特殊性。但是呢,既然存在module这种东西,一定有它区别于常规对象的特性。那么什么是一切ruby对象所共有的属性,module作为一种特殊的对象又有哪些特性呢?本篇就以此为线索逐步深入论述ruby的对象模型。

首先,一切ruby对象,无论它是否是module,都允许持有实例变量(instance variable)。而这些实例变量作为构成ruby对象的一部分,只与该对象相关联。这一点看似平淡无奇,实则很有意思。如果读者对市面上的主流面向对象编程语言有所了解,就能品出这里面的味道。比如在Java中,一个对象包含哪些实例变量,是由作为该对象的模板的类所定义的,Java对象只能决定其所持有的实例变量的值,却不能左右所持有的实例变量的类型与数目。而ruby则不同,实例变量只附属于对象,而与对象所属的类没有任何瓜葛。

等等,刚才不是只提到ruby的对象分为常规对象和module吗,怎么又多出一个类(class)呢?这就不得不提到ruby对象的另一个共性——每个ruby对象都有一个它所属的类——而所谓类,其实也是一种对象,并且类(Class)是模块(Module)的子类。

如果你被上面这句话绕蒙了,很正常,但是读完这篇文章相信你会豁然开朗,你会发现原来ruby是如此令人着迷。
前面在提到模块的时候,都是用的小写的module,但其实真正作为一个实实在在的ruby对象的是大写的Module。二者的区别非常重要,请读者细心领会,前者是泛指一类对象,对象的名字可以是Hello,可以是Ok,但是它们都属于module,或者说它们是Module的实例,反过来说就是它们的类(class)是Module。这样说来Module是一个类(class)了?没错,Module是一个类,而类也是对象,所以Module是一个实实在在的ruby对象,它的名字就是Module。如果你还没晕,那么请继续往下看。

前面提到过Class是Module的子类,这又是怎么回事呢?注意这里的Class同样区别于小写的class,后者是泛指类这种对象,名字可以是Hello,可以是Ok,但是它们都是Class的实例,或者说它们的类是Class。可以这么说,如果一个对象,它的类是Class,那么它就不是常规的对象,而是一个类(class)。而至于这个大写的Class,它与Module一样,是一个不折不扣的ruby对象,在作为ruby对象这一点上,正如开篇所言,ruby只有一种类型的对象,也就是说无论是module,Module,class还是Class,在作为ruby对象这一点上,它们与常规对象并没有区别。那么区别在哪呢?

为了对本篇所阐述的内容有一个直观的认识,读者可以使用交互式ruby解释器irb。如果安装了ruby,那么在命令终端敲irb就可以进入irb环境。读者可以利用irb进行一些试验。首先敲下面这行命令

mod=Module.new

笔者得到的结果是

=> #<Module:0x007ff49184c8e8>

意思是mod是Module的一个实例,反过来Module应该是mod的类,我们看看是不是这样,输入

mod.class

结果为

=> Module

可见Module是一个类(class),前面说过如果某个对象是一个类,意味着它的类为Class,我们仍然可以用irb进行验证

Module.class
=> Class

如果读者好奇Class的类是什么,也可以通过irb得到答案,其实答案很显然,既然Class也是一个类,那么自然地Class.class等于Class。
然后我们再做下面的试验

cl=Class.new
=> #<Class:0x007fa0920670b8>
cl.class
=> Class

读者对输出结果应该不会感到意外。到这里我们差不多可以小结一下了。首先,Module和Class都是类,这样说等价于Module.class => Class以及Class.class => Class,这正是这二者区别于常规对象的地方,一般地对于常规对象obj,obj.class的输出不会是Class,至于是什么,当然是程序员自己定义的。如果你已经定义了一个类

class Obj
end

然后新建一个属于该类的对象

obj=Obj.new

那么显然obj.class => Obj

如果读者已经读到了这里,那么对于ruby中对象是什么,类是什么,类与对象的关系是什么应该已经有了一个基本的认识,悬而未决的是对象和类里面究竟有什么,module究竟是什么。读下去你会得到这些问题的答案。
我们先来看一下ruby对象的方法。下面这段论述取自笔者的回答。

一个ruby对象可以调用的方法有两类。
一类是定义于该对象的class中,叫instance method,比如

def last_updated_at
    #blahblah
end

那么Category的实例便可以调用该方法,而Category本身不可以

category1=Category.new
category2=Category.new
category1.last_updated_at    #legal
category2.last_updated_at    #legal
Category.last_updated_at    #illegal

另一类叫singleton method,它只能被一个对象调用,该对象的类不可以,与该对象同属一个类的其他对象也不可以。singleton
method的定义方式如下

#category1=Category.new
def category1.last_updated_at
    #blahblah
end

这样定义之后,只有category1这个对象才可以调用last_updated_at方法

category1.last_updated_at    #legal
category2=Category.new
category2.last_updated_at    #illegal
Category.last_updated_at    #illegal

ruby的类也是对象,也可以定义它自己的singleton method,比如

def Category.last_udpated_at
    #blahblah
end

这样一来只有Category可以调用last_updated_at方法,而它的实例不可以,其他类也不可以,确切说任何其他对象都不可以

Category.last_updated_at    #legal
category=Category.new
category.last_updated_at    #illegal

在Category类的定义内部(方法的外部),self指代Category本身,故而

def Category.last_udpated_at
    #blahblah
end

可以替换成

def self.last_udpated_at
    #blahblah
end

这便是你问题中定义的那个方法。现在明白了吧?实质上它是Category的singleton
method,而Category是一个类,类的singleton method又称为该类的class method,只能由该类本身调用。
需要注意的是,class method就是singleton method,只不过它是一个类的singleton
method,除此之外并没有什么特别之处。就像instance method由对象所属的class持有,singleton
method也由对象的一个叫eigenclass的东西持有。关于eigenclass还有很多学问,这里就不提了。我会在文章里讲一下。

未完待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值