学无所长,一事无成
分类: Python/Ruby
2012-07-11 00:20:55
1.2 打开类技术
类可以直接用 class 打开,因此你可以任意往现有类中添加方法(注意有可能覆盖同名方法),当然这不是一种好的风格,但你有这种能力,在某些情况下你可以获得特殊的效果。
class 关键字更像是一个作用域操作符,而非类型声明语句。class确实可以创建一个还不存在的类,不过这更像是一种副作用,其核心任务还是把你带到类的上下文当中。
打开类所带来的问题
如果你为某个已知类添加方法,可能会将该类的原有方法覆盖。这种鲁莽的方式令人不悦,我们一般管这种行为叫猴子补丁 Monkey patch。由于类可以在任何地方打开,因此猴子补丁在代码庞大时可能难以追踪。一般我们可以通过命名空间来限定其影响范围。
1.3 类的真相
对象中有什么
1、实例变量:Ruby 中对象的类和它的实例变量没有关系。对同一个类,你可以创建具有不同实例变量的对象。
2、方法:一个对象仅仅包含它的实例变量以及一个对自身类的引用。方法存在于类当中,而非对象中。
对象的方法实际上是其类的实例方法,如:
- String.instance_methods == “abc”.methods # true,等式成立
- String.methods == “abc”.methods # false ,等式不成立;注:String 有双重身份,既是类,同时也是对象。
总结:一个对象的实例变量存在于对象本身,而一个对象的方法存在于对象自身的类中。
重访类
类自身也是对象,它是 Class 类的实例对象。
- 'abcd'.class # => String
- String.class # => Class
一个对象的方法也是其类的实例方法。
- inherited = false
- Class.instance_methods(inherited) # =>[:superclass,:allocate,:new]
- String.superclass # => object
- Object.superclass # => BasicObject
- BasicObject.superclass # => nil
所有类都继承于 Object ,Object 又继承于 BasicObject (这本质上就是一个白板类,用作模板)。Class 同样具有父类。
- Class.superclass # => Module
- Module.superclass # => Object
这里,我已经彻底困惑了,到底是先有鸡,还是先有蛋,也许学到后面就明白了。实际上,这里体现出两种关系,父类同子类的关系,对象同类的关系。
一个类不过是一个增强的 Module ,在其上增加了三个方法 – new 、allocate 、superclass 而已。除此之外,Class 同 Module 基本上一样的。绝大多数适用于 Class 的,同样也适用于 Module ,反之亦然。
就像类是对象一样,类名也无非就是常量
这里 Module(也是常量) 还有 Class (也是常量) 可以想象成目录,其他常量可以想象成文件,因此我们可以这样引用一个常量:
这是两个不同的常量。
就像用目录来组织文件一样,我们可以用模块来组织常量。
来自Rake 的例子 – p17
通过此方式,我们定义了一个 Rake::Task 名字空间,有效避免了命名冲突。
前面说过常量类似于文件系统中的目录和文件,那我们是不是可以创建目录和文件的链接呢(类似于 unix 下的 ln 指令),这完全可以:
常量的路径:通过 :: 分隔,可以在常量前面加上 :: 表示根路径,如 ::Rake::Task::xxx
Module 类提供了两个角 constants() 的方法,一个是实例方法,一个类方法。Module#constants() 方法返回当前范围内的常量,有点像unix 的 ls 指令。Module.constants() 方法返回当前程序中所有顶级常量,包括类名。
这个概念理解较为困难,参考如下文章:
http://www.kuqin.com/rubycndocument/man/built-in-class/class_object_module.html#constants
如果想获得当前常量的路径,则可以使用 Module.nesting() 方法:
修剪常量树 – P19
load(‘motd.rb’) 会加载文件并运行,motd.rb 中定义的常量和类会污染当前作用域。因此可以如下
load(‘motd.rb’,true) # true ,强制加载文件中的常量仅在自身范围内有效。Ruby 会创建一个匿名模块,使用它作为命名空间。加载完成后,该模块销毁。
require 同 load 颇为相似,但它导入文件后不执行。
对象和类的小结:
1、对象 = 实例变量 + 指向其类的引用。对象的方法存在于类中,在类中,被称为类的实例方法。
2、类 = Class 类的一个实例对象 + 一组实例方法(即该类的实例方法) + 指向超类的引用。 Class 是 Module 的子类,因此一个类也是一个模块。
3、类有自己的方法(如 new(),即我们通常所说的类方法),这些是 Class 类的实例方法。
类名 = 常量 = 指向 Class 类实例对象的引用
比如 String 是个类名,同时也是个常量,同时也是 Class 的实例对象 (可以通过 Class.new 生成)
1.5 方法查找
调用 obj.func 时的步骤:obj 为接受者,func 为方法。
“向右一步,再向上”。先向右一步来到接受者所在的类,然后沿着祖先链向上直到找到给定的方法。