ruby中的方法調用都是 對象.方法 的形式,那麼對象如何找到這個方法呢?ruby
首先必須瞭解祖先鏈的概念,祖先鏈就是從一個類開始,到它的父類,再到父類的父類...一直到最終的起點(ruby中是BasicObject類)。這期間經歷過的路徑就是祖先鏈。函數
1混含模塊和繼承的方法查找this
對於一個實例對象,先找它屬於的類中是否有對應的實例方法,而後看這個類中是否有模塊,若是有,查找模塊中是否有對應的方法,若是沒有,則查找父類。先看父類的實例方法,再看父類中是否有模塊,再看父類的父類..一直到最後,BasicObject類和Kernel模塊。spa
若是尚未,則會去查看method_missing函數,這個函數是內建函數。這個函數默認是報錯,固然你也能夠重寫這個方法,來對沒有找到的方法在其中進行處理。code
以下:對象
1 module M 2 def method 3 puts "this is method in module M" 4 end 5 end 6 7 class C 8 include M 9 end 10 11 class D < C;end 12 13 D.new.method 14 p D.ancestors
輸出是blog
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中的全部對象均可以用這個方法。class
2含有多個相同的方法時的方法查找
含有多個相同的方法時,會匹配第一個找到的方法。
以下:
1 module M 2 def method 3 puts "this is method in module M" 4 end 5 end 6 7 module N 8 def method 9 puts "this is method in module N" 10 end 11 end 12 13 class C 14 include M 15 include N 16 end 17 18 C.new.method 19 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中的每一個對象實際上都有兩個類:多個對象實例共享的類和單例類。對象調用的方法,就是這兩個類中的實例方法,以及祖先類和混含模塊中的方法。
有單例類的時候,對象的方法查找先查找單例類,而後是單例類混含的模塊,而後是對象所屬的類,以此類推。
單例類的父類是對象所屬的類。
以下:
1 module M 2 def method 3 puts "this is method in module M" 4 end 5 end 6 7 class C 8 end 9 10 c = C.new 11 class << c 12 def method 13 puts "this is method in c' singleton class" 14 end 15 include M 16 p ancestors 17 end 18 19 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
以下:
1 module M 2 end 3 class C 4 include M 5 end 6 c = C.new 7 class << c 8 include M 9 p ancestors 10 end 11 p C.ancestors
輸出結果是:
[C, M, Object, Kernel, BasicObject]
[C, M, Object, Kernel, BasicObject]
單例類裏混含的模塊沒有出如今祖先鏈裏,c的單例類和類C的祖先鏈同樣了。
假設類C中包含的不是模塊M,而是另外一個模塊N。
以下:
1 module M 2 end 3 module N 4 end 5 class C 6 include N 7 end 8 c = C.new 9 class << c 10 include M 11 p ancestors 12 end 13 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類方法的單例類
上面講的是實例對象的單例類。若是是類的單例類呢?(每個對象都有單例類,類也是對象,固然也有單例類,類方法就是放在單例類裏的。)
單例類不能被繼承,可是單例類是能夠有父類或者子類的。
以下:
1 class C 2 def self.method 3 p "This is method in C" 4 end 5 end 6 class D < C 7 end 8 D.method 9 10 en = class << C;self;end 11 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