日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
理解Ruby2.0中方法是如何查找與執(zhí)行

預(yù)先介紹Ruby2.0是一個(gè)好的機(jī)會(huì)去回顧如何精確的用Ruby去樹立方法調(diào)用。

理解查找方法對(duì)于掌握Ruby的層次類是很有必要的。我準(zhǔn)備的這篇文章有很多的代碼例子;你需要用Ruby 1.9.2 或者 更新的版本去調(diào)試運(yùn)行大部分的例子,這有一個(gè)預(yù)先準(zhǔn)備好的,它只能夠運(yùn)行在Ruby2.0.0

類層次結(jié)構(gòu)

讓我們以基類的繼承這一經(jīng)典的例子開始吧

 
 
 
  1. class Animal  
  2.   def initialize(name)  
  3.     @name = name  
  4.   end  
  5.  
  6.   def info  
  7.     puts "I'm a #{self.class}." 
  8.     puts "My name is '#{@name}'." 
  9.   end  
  10. end  
  11.  
  12. class Dog < Animal  
  13.   def info  
  14.     puts "I #{make_noise}." 
  15.     super 
  16.   end  
  17.  
  18.   def make_noise  
  19.     'bark "Woof woof"' 
  20.   end  
  21. end  
  22.  
  23. lassie = Dog.new "Lassie" 
  24. lassie.info  
  25. # => I bark "Woof woof".  
  26. #    I'm a dog.  
  27. #    My name is 'Lassie'. 

在這個(gè)例子中,狗這個(gè)類繼承于動(dòng)物類. 我們把動(dòng)物類稱之為狗的超級(jí)類:

 
 
 
  1. Dog.superclass # => Animal 

記住這個(gè)方法 Dog#info 調(diào)用超級(jí)類,這個(gè)特殊的關(guān)鍵字執(zhí)行了后面接著的這個(gè)層次的定義,像這個(gè)例子  Animal#info 這個(gè)類可以用繼承類的屬性

 
 
 
  1. Dog.ancestors # => [Dog, Animal, Object, Kernel, BasicObject] 

繼承類不以Animal結(jié)尾時(shí)很令人感興趣的地方

 
 
 
  1. Animal.superclass # => Object 

這個(gè)Animal類的申明相當(dāng)于之前寫了一個(gè)Animal類的對(duì)象

這就是為什么動(dòng)物藥擁有比make_noise更多的方法,尤其反思的方法像是 respond_to?方法等等:

 
 
 
  1. lassie.respond_to? :upcase # => false 
  2. lassie.methods  
  3.  # => [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, ...] 

因此怎么引出內(nèi)核和基本對(duì)象呢?待會(huì)我將回談到內(nèi)核,事實(shí)上并不會(huì)說太多的基本對(duì)象之外的東西只有有限數(shù)量的方法并且會(huì)以所有類的層次結(jié)構(gòu)收尾。

 
 
 
  1. # BasicObject is the end of the line:  
  2. Object.superclass # => BasicObject  
  3. BasicObject.superclass # => nil  
  4. # It has very few methods:  
  5. Object.instance_methods.size # => 54 
  6. BasicObject.instance_methods.size # => 8 

類是形成一棵樹的根莖所在

Mixins

雖然Ruby只支持單根繼承(也就是說,一個(gè)類只有一個(gè)超類),但它支持 mixins. mixin是一組可以包含到其他類的方法。在Ruby,實(shí)現(xiàn)為Module類:

 
 
 
  1. module Mamal  
  2.   def info  
  3.     puts "I'm a mamal" 
  4.     super 
  5.   end  
  6. end  
  7. Mamal.class # => Module 

要在我們的Dog類中加入這個(gè)功能,我們可以用include 或者 prepend. 它們會(huì)插入這個(gè)module在Dog類之前或者之后:

 
 
 
  1. class Dog  
  2.   prepend Mamal  
  3. end  
  4. lassie = Dog.new "Lassie" 
  5. lassie.info  
  6. # => I'm a mamal.  
  7. #    I bark "Woof woof".  
  8. #    I'm a dog.  
  9. #    My name is 'Lassie'.  
  10. Dog.ancestors # => [Mamal, Dog, Animal, Object, ...] 

如果這個(gè)module被include到Dog類,而不是prepend到Dog類,效果類似,但是輸出的順序不一樣,你能猜到結(jié)果和祖先(ancestors)輸出的循序嗎?  點(diǎn)擊這里看結(jié)果  .

你可以隨意包含任意多個(gè) include 和 prepend 的module。module還可以include和 prepende 其他module。當(dāng)你不確定module和類得繼承體系時(shí),馬上調(diào)用ancestors搞清楚。

單件類

在Ruby里, 在module和類得體系中,只有一個(gè)額外的層。任意對(duì)象可以有一個(gè)特殊的類優(yōu)先于任何事:?jiǎn)渭悾?em>singleton class)

下面有個(gè)例子:

 
 
 
  1. scooby = Dog.new "Scooby-Doo" 
  2.  
  3. class << scooby  
  4.   def make_noise  
  5.     'howl "Scooby-Dooby-Doo!"' 
  6.   end  
  7. end  
  8. scooby.info  
  9. # => I'm a mamal.  
  10. #    I howl "Scooby-Dooby-Doo!".  
  11. #    I'm a dog.  
  12. #    My name is 'Scooby-Doo'. 

請(qǐng)注意復(fù)吠叫那部分(I bark "Woof woof".)被史酷比特殊的嚎叫()代替了I howl "Scooby-Dooby-Doo!".那這不會(huì)影響Dog類得其他實(shí)例。

"class << scooby"是重新打開一個(gè)對(duì)象的單件類的特殊記法。還有一個(gè)方法可以定義單件方法:

 
 
 
  1. # 和上面的例子等同:  
  2. def scooby.make_noise  
  3.   'howl "Scooby-Dooby-Doo!"' 
  4. end 

單件類是個(gè)真正的類,可以通過調(diào)用singleton_class來訪問:

 
 
 
  1. # 單件類有個(gè)特別的名字:  
  2. scooby.singleton_class # => #>  
  3. # 單件類是個(gè)真正的類:  
  4. scooby.singleton_class.is_a?(Class) # => true 
  5. # 我們可以得到它實(shí)例方法的列表:  
  6. scooby.singleton_class.instance_methods(false) # => [:make_noise] 

所有Ruby對(duì)象都可以有單件類,包括類它們自己,甚至單件類自己也可以有單件類。

這聽起來有些瘋狂...那不是需要無數(shù)個(gè)單件類???某種意義上講,是的,但是Ruby會(huì)在他們需要的時(shí)候再去創(chuàng)建。

雖然上個(gè)例子是使用Dog類的一個(gè)實(shí)例的單件類。單更見的用在類上。. 實(shí)際上, "  類方法  " 就是單件類得方法。例如,attr_accessor 是Module單件類的一個(gè)實(shí)例方法。 Ruby on Rails 中的 ActiveRecord::Base 類有很多這樣的方法例如 has_many, validates_presence_of,  等等。下面可以看到ActiveRecord::Base的單件類的方法個(gè)數(shù):

 
 
 
  1. Module.singleton_class  
  2.       .private_instance_methods  
  3.       .include?(:attr_accessor) # => true 
  4.  
  5. require 'active_record' 
  6. ActiveRecord::Base.singleton_method  
  7.                   .instance_methods(false)  
  8.                   .size  # => 170 

單件類的名字來源于,他們有且只能有一個(gè)實(shí)例:

 
 
 
  1. scooby2 = scooby.singleton_class.new 
  2.   # => TypeError: can't create instance of singleton class 

因?yàn)橥瑯拥脑?,你不能直接繼承一個(gè)單件類:

 
 
 
  1. class Scoobies < scooby.singleton_class  
  2.   # ...  
  3. end  
  4. # => TypeError: can't make subclass of singleton class 

另一方面,單件類有一個(gè)完整的類體系。

對(duì)于對(duì)象;來說,我們有:

 
 
 
  1. scooby.singleton_class.superclass == scooby.class == Dog  
  2.  # => true, as for most objects 

對(duì)于類來說,Ruby會(huì)自動(dòng)設(shè)置超類,所以穿越超類或者單點(diǎn)類的不同路徑都相等:

 
 
 
  1. Dog.singleton_class.superclass == Dog.superclass.singleton_class  
  2.  # => true, as for any Class 

這意味著Dog繼承Animal的實(shí)例方法以及它的單件方法。

為了徹底搞暈大家,我***寫下個(gè)extend的注解。它可以看做在被擴(kuò)展對(duì)象的單件類include一個(gè)module的簡(jiǎn)寫3:

 
 
 
  1. obj.extend MyModule  
  2. # is a shortcut for  
  3. class << obj  
  4.   include MyModule  
  5. end 

Ruby's 單件類遵從 eigenclass model.

方法查找和方法缺失

差不多都講完了!

Ruby支持的豐富的被繼承鏈?zhǔn)撬蟹椒ú檎业幕A(chǔ)。

當(dāng)查找到***的超類(BasicObject), Ruby 提供一個(gè)額外的方法處理方法缺失。

 
 
 
  1. lassie.woof # => NoMethodError: undefined method  
  2.   # `woof' for #  
  3.  
  4. class Animal  
  5.   def method_missing(method, *args)  
  6.     if make_noise.include? method.to_s  
  7.       puts make_noise  
  8.     else 
  9.       super 
  10.     end  
  11.   end  
  12. end  
  13.  
  14. lassie.woof # => bark "Woof woof!" 
  15. scooby.woof # => NoMethodError ...  
  16. scooby.howl # => howl "Scooby-Dooby-Doo!" 

在上面的例子,當(dāng)方法名是動(dòng)物弄出來的噪音的一部分,我們調(diào)用make_noise,否則我們調(diào)用超類。超類會(huì)繼續(xù)向祖先查找知道到達(dá)BasicObject#method_missing,然后扔出NoMethodError 異常。

#p#

總結(jié)

總結(jié)一下,在Ruby中,當(dāng)調(diào)用receiver.message 將會(huì)發(fā)生:

·沿著 receiver.singleton_class' 祖先鏈發(fā)送消息。

·然后沿著同樣的祖先鏈發(fā)送method_missing(消息)

在其中,***個(gè)找到的方法執(zhí)行,并返回結(jié)果。任何對(duì)父類的調(diào)用重新恢復(fù)查找過程,找第二次符合的方法。

一個(gè)Module mod的祖先鏈?zhǔn)?

·每一個(gè)被它prepend的module的祖先鏈 (后prepend的module先查找)

·mod 它自己

·每一個(gè)被include的module的祖先鏈 (后include的module先查找)

·mod是個(gè)類,那就接下來查找它的超類的祖先鏈。

我們可以把上面的過程寫成偽碼4:

 
 
 
  1. class Module  
  2.   def ancestors  
  3.     prepended_modules.flat_map(&:ancestors) +  
  4.     [self] +  
  5.     included_modules.flat_map(&:ancestors) +  
  6.     is_a?(Class) ? superclass.ancestors : []  
  7.   end  
  8. end 

寫出實(shí)際的查找過程更復(fù)雜,但看起來大致像:

 
 
 
  1. class Object  
  2.   def send(method, *args)  
  3.     singleton_class.ancestors.each do |mod|  
  4.       if mod.defines? method  
  5.         execute(method, for: self, arguments: args,  
  6.           if_super_called: resume_lookup_at(mod))  
  7.       end  
  8.     end  
  9.     send :method_missing, method, *args  
  10.   end  
  11.  
  12.   def method_missing(method, *args)  
  13.     # This is the end of the line.  
  14.     # If we're here, either no method was defined anywhere in ancestors,  
  15.     # and no method called 'method_missing' was defined either except this one,  
  16.     # or some methods were found but called `super` when there was  
  17.     # no more methods to be found but this one.  
  18.     raise NoMethodError, "undefined method `#{method}' for #{self}" 
  19.   end  
  20. end 

技術(shù)注腳

1 mixin有一些限制:

·Ruby對(duì)于同樣的module出現(xiàn)多次的體系支持的不是很好, hierarchy.ancestors 只會(huì)列出一個(gè)module一次,即使它被包含在祖先的  不同的層次  . 我還是很希望未來這個(gè)問題會(huì)解決,尤其為了避免 讓人尷尬的bug

·包含子模塊在模塊 M 不會(huì)影響之前包含模塊M的類,但是會(huì)影響之后包含模塊M的類。 請(qǐng)看這里.

·而且,Ruby 不允許祖先鏈包含循環(huán)。

2 Ruby實(shí)際上禁止對(duì)下面少數(shù)幾個(gè)類得單件類的訪問:Fixnum,Symbol 和 (從Ruby 2.0開始)Bignum 和 Float:

 
 
 
  1. 42.singleton_class # => TypeError: can't define singleton 

作為經(jīng)驗(yàn),立即數(shù)不能有單件類. 因?yàn)?1 << 42).class 是Fixnum 如果平臺(tái)是64位,否則是Bignum,對(duì)于Bignum也同樣適用。同樣的Ruby2.0后對(duì)于Float也同樣適用,因?yàn)橐恍└↑c(diǎn)數(shù)也可能是立即數(shù).

唯一的例外是nil,true 和false,他們的單件類是他們自己的類:nil.singleton_class 是 NilClass.

3 更準(zhǔn)確的說,extend和單件類包含 缺省有同樣的效果,單他們調(diào)用不同的回調(diào):extended vs included,append_features vs extend_object. 如果這些回調(diào)定義的不同,效果也最終會(huì)不同。

4 注意,prepended_modules不存在. 同樣singleton_class.ancestors 也不包含單件類自己, 但這個(gè)情況 會(huì)在Ruby 2.1改變 .

原文鏈接:http://www.oschina.net/translate/understanding-method-lookup-in-ruby-20#fn_extend


名稱欄目:理解Ruby2.0中方法是如何查找與執(zhí)行
當(dāng)前地址:http://www.5511xx.com/article/dhjjpds.html