ruby中的方法调用都是 对象.方法 的形式,那么对象如何找到这个方法呢?

  首先必须了解祖先链的概念,祖先链就是从一个类开始,到它的父类,再到父类的父类...一直到最终的起点(ruby中是BasicObject类)。这期间经历过的路径就是祖先链。

  1混含模块和继承的方法查找

  对于一个实例对象,先找它属于的类中是否有对应的实例方法,然后看这个类中是否有模块,如果有,查找模块中是否有对应的方法,如果没有,则查找父类。先看父类的实例方法,再看父类中是否有模块,再看父类的父类..一直到最后,BasicObject类和Kernel模块。

  如果还没有,则会去查看method_missing函数,这个函数是内建函数。这个函数默认是报错,当然你也可以重写这个方法,来对没有找到的方法在其中进行处理。

如下:

 module M
def method
puts "this is method in module M"
end
end class C
include M
end class D < C;end D.new.method
p D.ancestors

输出是

this is method in module M
[D, C, M, Object, Kernel, BasicObject]

  如这个例子,类D的对象D.new要找method方法:先找D中的实例方法,没有,D中也没有模块。D的父类是C,先找C的实例方法,没有,但C中有模块M,模块M中有method方法,这样就找到了。这个顺序就是按照祖先链的顺序。

  这种查找能到什么程度呢?如祖先链表示的,接下来就是Object类,这是ruby中一切对象的开始。其中有一个模块Kernel。也就是说,如果你在Kernel中定义了一个方法,那么ruby中的所有对象都可以用这个方法。

  2含有多个相同的方法时的方法查找

  含有多个相同的方法时,会匹配第一个找到的方法。

如下:

 module M
def method
puts "this is method in module M"
end
end module N
def method
puts "this is method in module N"
end
end class C
include M
include N
end C.new.method
p C.ancestors

输出结果

this is method in module N
[C, N, M, Object, Kernel, BasicObject]

  类C中包含两个模块M和N,M和N都有method方法。那么调用哪个呢?如果在同一个类中,ruby中新定义的方法会覆盖旧的方法。类似的,模块N相对M是后混如类C的,所以会调用N中的方法。另一个方面,从祖先链来看,N也是排在M的前面,因此也是先调用N的方法。

  祖先链中是模块是怎么排序的呢?祖先链中,一个模块M恰好在包含它的类C中的上一个位置。如这个例子,类C先包含了M,祖先链中是C,M。然后又包含了N,N又恰好在C的上一个位置,于是就变成了C,N,M。

  3包含单例类的方法查找

  前面的两种情况是不含单例类的情况,如果含有单例类,就要先考虑单例类了。

  单例类:简单的说就是某个对象特有的类。它只能属于一个对象(即使是同一个类的其他对象实例也不行),因此称为单例类。

  ruby中的每个对象实际上都有两个类:多个对象实例共享的类和单例类。对象调用的方法,就是这两个类中的实例方法,以及祖先类和混含模块中的方法。

  有单例类的时候,对象的方法查找先查找单例类,然后是单例类混含的模块,然后是对象所属的类,以此类推。

  单例类的父类是对象所属的类。

如下:

 module M
def method
puts "this is method in module M"
end
end class C
end c = C.new
class << c
def method
puts "this is method in c' singleton class"
end
include M
p ancestors
end c.method

输出是

[M, C, Object, Kernel, BasicObject]
this is method in c' singleton class

  单例类,并没有在祖先链中表示出来,但是调用的方法确实是单例类的方法。然后是混含的模块M,然后是父类,以此类推。从祖先链可以看出,单例类的父类是C,是对象c所属的类。


  HELP

  在这里出现了一个问题,假如类C中也包含类模块M,那祖先链理论上说应该是M,C,M,Object,Kernel,BasicObject

如下:

 module M
end
class C
include M
end
c = C.new
class << c
include M
p ancestors
end
p C.ancestors

输出结果是:

[C, M, Object, Kernel, BasicObject]
[C, M, Object, Kernel, BasicObject]

  单例类里混含的模块没有出现在祖先链里,c的单例类和类C的祖先链一样了。

  假设类C中包含的不是模块M,而是另一个模块N。

如下:

 module M
end
module N
end
class C
include N
end
c = C.new
class << c
include M
p ancestors
end
p C.ancestors

输出结果

[M, C, N, Object, Kernel, BasicObject]
[C, N, Object, Kernel, BasicObject]

  此时,结果和我预期的一样。祖先链中仍然是有c的单例类混含的模块M的。

  这是为什么呢?难道是说,如果单例类里和祖先链上的其他类混含了同样的模块,单例类中的模块名字不显示了?

  另外我也在类Object中包含了M,结果是[C, N, Object, M, Kernel, BasicObject],c的单例类中的模块M也没有。如果是包含N,结果是[M, C, N, Object, N, Kernel, BasicObject],又和预期的一样。难道是单例类和祖先链上的其他类不能包含同样的模块?

  我知道非单例类是可以包含同名的模块的,而且可以同时出现在祖先链里。(我用的是ruby1.9.3)

  路过懂得求解答,不胜感激。


  4类方法的单例类

  上面讲的是实例对象的单例类。如果是类的单例类呢?(每一个对象都有单例类,类也是对象,当然也有单例类,类方法就是放在单例类里的。)

单例类不能被继承,但是单例类是可以有父类或者子类的。

如下:

 class C
def self.method
p "This is method in C"
end
end
class D < C
end
D.method en = class << C;self;end
class E < en;end;

输出结果

"This is method in C"
can't make subclass of singleton class (TypeError)

  结果显示,D.method调用的是C的单例方法,说明D的单例类继承了C的单例类,是它的子类。但是从10-11行,可知,单例类是不能被继承的。

  我觉得可以这么认为:在D继承C的时候,D的单例类继承了C的单例类,所以D可以调用C的类方法。同理,D也可以调用Object类的类方法。

  整理一下:

  类的实例对象的方法查找,先找单例类,然后单例类中的模块。再找父类,父类中的模块。以此类推。

  类对象的方法查找,先找单例类(就是类方法),再找父类的单例类,以此类推。

  如果找到多个方法,以找到的第一个方法匹配。

  ruby中,一个类不能被继承,它也可以有子类。例如ruby中类的单例类。

  如果我们用superclass来找父类的话,可得(#代表单例类,假设d是类D的对象,类D继承类C,->表示父类是)

#d->D->C->Object->BasicObject->nil

       #D->#C->#Object->#BasicObject->Class->Module->Object->BasicObject->nil

  

ruby中的方法查找的更多相关文章

  1. ruby中的可调用对象--方法

    上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...

  2. Ruby中方法的设计理念

    Ruby中的方法命名遵从与局部变量相同的规则和约定.这是一种设计理念:方法并不因其自身作为方法而被人关注,而是简单地作为提供值的表达式融入到程序的结构中.

  3. ruby中的可调用对象--proc和lamdba

    ruby中将块转变成对象的三种方法 ruby中的大部分东西都是对象,但是块不是.那么,如果你想存下来一个块,方便以后使用,你就需要一个对象.ruby中有三种方法,把块转换成可以利用的对象. Proc. ...

  4. ruby语法之方法

    ruby中的方法相当于python的函数 其定义规则为: 方法名应以小写字母开头.如果您以大写字母作为方法名的开头,Ruby 可能会把它当作常量,从而导致不正确地解析调用. 方法应在调用之前定义,否则 ...

  5. ruby中的回调方法和钩子方法

    在ruby中,当某些特定的事件发生时,将调用回调方法和钩子方法.事件有如下几种: 调用一个不存在的对象方法 类混含一个模块 定义类的子类 给类添加一个实例方法 给对象添加一个单例方法 引用一个不存在的 ...

  6. 【转】Java中字符串中子串的查找共有四种方法(indexof())

    原文网址:http://wfly2004.blog.163.com/blog/static/1176427201032692927349/ Java中字符串中子串的查找共有四种方法,如下:1.int ...

  7. Java中字符串中子串的查找共有四种方法(indexof())

    Java中字符串中子串的查找共有四种方法(indexof()) Java中字符串中子串的查找共有四种方法,如下:1.int indexOf(String str) :返回第一次出现的指定子字符串在此字 ...

  8. ruby中顶层定义的方法究竟放在哪里?

    ruby中顶层(top level)中定义的方法放在main中,证明如下: self.private_methods(false) #IN TOP LEVEL 那么methods方法究竟是在哪定义的, ...

  9. ruby中如何调用与局部变量同名的私有方法

    如果ruby中一个局部变量名和私有方法名同名的话,默认该名称被解释为变量而不是方法: x=10; def x;puts "what?" end 当你输入x实际不能执行x方法.解释器 ...

随机推荐

  1. JQuery------鼠标双击时,不选中div里面的文字

    如图:(去掉选中文字的蓝色背景色) 代码: //方法一:<div class="test" onselectstart="return false" &g ...

  2. 权限模块_使用权限_实现主页面的效果_显示左侧菜单&只显示有权限的菜单项

    权限模块__使用权限__实现主页面的效果 HomeAction.java public class HomeAction extends ActionSupport { public String i ...

  3. 剑指 offer set 13 把数组排成最小的数

    总结 1. 给定 3, 32, 321 将他们组合成最小的数, 比如 321323 2. 3    ->   333 32   ->   322 321 ->   321 然后再排序

  4. NUC972 MDK NON-OS

     NUC972直接可以在BSP包里模板进行编程,烧录用Nu writer  http://www2.keil.com/mdk5/legacy 下载对应的安装包的插件 是直接下载到DDR 里面去运行,所 ...

  5. uva 110 Meta-Loopless Sorts 用程序写程序 有点复杂的回溯水题

    题目要求写一个直接用比较排序的pascal程序,挺有趣的一题. 我看题目数据范围就到8,本来以为贪个小便宜,用switch输出. 然后发现比较次数是阶乘级别的,8的阶乘也是挺大的,恐怕会交不上去. 于 ...

  6. ORACLE WITH AS 用法,创建临时表

    语法: with tempName as (select ....) select ... –针对一个别名with tmp as (select * from tb_name) –针对多个别名with ...

  7. Javascript-const 常量

    const 常量 常量是块级作用域,很像使用 let语句定义的变量.常量的值不能通过重新赋值来改变,并且不能重新声明. 此声明创建一个常量,其作用域可以是全局或本地声明的块. 与var变量不同,全局常 ...

  8. Spoken English Practice(Don't get me wrong, that explanation makes no difference, I'm still mad at you. Come on, be reasonable!)

    绿色:连读:                  红色:略读:               蓝色:浊化:               橙色:弱读     下划线_为浊化 口语蜕变(2017/7/11) ...

  9. _init_() got an unexpected keyword argument ‘shape’

    按照<TensorFlow:实战Google深度学习框架>一书学习的tensorflow,书中使用的是0.9.0版本,而我安装的是1.11.0 如果按照书上的例子来,因为这本书使用tens ...

  10. 预见未来丨机器学习:未来十年研究热点 量子机器学习(Quantum ML) 量子计算机利用量子相干和量子纠缠等效应来处理信息

    微软研究院AI头条 https://mp.weixin.qq.com/s/SAz5eiSOLhsdz7nlSJ1xdA 预见未来丨机器学习:未来十年研究热点 机器学习组 微软研究院AI头条 昨天 编者 ...