都说 Ruby 是一个完全面向对象的编程语言,但,你知道这是什么意思吗 ? 在写下文字的这一刹那,笔者也是迷茫的。 不过没关系,我们可以慢慢学,慢慢的去了解 Ruby 中的对象模型 ( object model )
祖先链 ( Ancestor Chain )
Ruby 面向对象中最重要的一环,就是 ancestors
方法,该方法没有任何参数,但会返回一个数组 ( Array ),这个数组里存储着该类 ( 对象 ) 的所有祖先链 ( 继承链上的所有类 )
「 祖先链 」是 Ruby 类层次结构的表现形式。按顺序,它包含了
- 当前被调用的类
- 调用的类所处在的模块
- 它的父类
- 它的父类所处在的模块
- 它父类的父类
- ... 以此类推
下面的代码显示了 Array 这个类的祖先链
irb> Array.ancestors # Array's ancestor chain => [Array, Enumerable, Object, Kernel, BasicObject] irb> Array.included_modules # Array included modules => [Enumerable, Kernel] irb> Array.superclass # the parent class => Object irb> Array.superclass.included_modules # parent's included modules => [Kernel] irb> Array.superclass.superclass # the grandparent class => BasicObject
Array::included_modules
返回一个数组 ( Array ) ,包含了祖先链中包含的所有模块,这也是为什么 Kernel
模块包含在 Array.included_modules
数组中的原因
祖先链和方法调用
当我们在对象内部调用某个方法时,Ruby 做的第一件事就是要确定你所调用的方法是否是存在于 self
上下文中 ( 也就是当前类是否有定义 )
如果没找到,它就会按照祖先链的顺序逐一找寻,知道找到为止。
下面的代码演示了这个查找过程
class Tiger def to_s "roar" end end irb> Tiger.new.to_s => "roar" # calls the #to_s method defined in the Tiger class irb> Tiger.inspect => "#<Tiger:0x007f>" # calls the #inspect method defined in Object ``` ## 对象类层次结构 ( Object class hierarchy ) `Object` 类是 Ruby 中所有类的默认父类。这句话的所代表的意思是,任何新创建的类默认都从 `Object` 类继承。 ```ruby class Child end Child.superclass => Object
那么,你也许会问,这个类的目的是什么 ?
有一个非常有意思的是,如果我们在 Object
上调用 ancestors
方法,它仍然会返回 Object
的祖先链
irb> Object.ancestors => [Object, Kernel, BasicObject]
也就是说 Object
还有自己的祖先链,它根本就不是那个最顶级的类 ?
BaseObject
BaseObject
是 Ruby 中所有类的最顶级的类。它只包含仅有的两个方法:对象创建和对象比较。
Kernel
Kernel
也包含在 Object
类中,它包含了所有的 「 对象操作 」 逻辑。
Object
由于 Kernel
模块包含了大多数方法,因此 Object
类更多的是作为它所有子类的一个接口 ( 得益于它的类名)。
main 对象
当一个新的 Ruby 程序启动时,Ruby 会自动创建一个 main
对象,它是 Object
类的一个实例。
main
对象是任意 Ruby 程序的顶级上下文,看起来这好像是对 C 的一种认可,因为 main()
函数是所有 C 语言程序的第一入口,Matz 喜欢 C
irb> self => main irb> self.class => Object
main
也是任意 Ruby 程序的顶级作用域,这意味着类/模块范围之外的任何指令都在 main
上下文中执行
irb> puts "main context" => main context
上面的代码中,puts
方法指的是私有的 Kernel#puts
方法,我们可以访问该方法,是因为 main
方法是 Object
的一个实例,该方法定义在 Kernel
模块中。
现在,让我们明确的尝试通过 self
访问 puts
方法 ( self
指的是 main
对象实例 )
irb> self.puts "main context" NoMethodError: private method `puts' called for main:Object
报错了,发生的原因是无法使用 接收器 调用私有方法 ( 在本例中为 self )
调用 self.puts
就像调用 main.puts
一样,因此上面的代码,就是尝试在类上下文之外调用 puts
。
换句话说,我们尝试将私有方法当作公共方法来调用。
结束语
Ruby 是一种完全面向对象的语言,因为从入口点( main
上下文)到程序结束,你将至少在都处在 main
对象的作用域之内