成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

理解Ruby2.0中方法是如何查找與執行

開發 后端
理解查找方法對于掌握Ruby的層次類是很有必要的。我準備的這篇文章有很多的代碼例子;你需要用Ruby 1.9.2 或者 更新的版本去調試運行大部分的例子,這有一個預先準備好的,它只能夠運行在Ruby2.0.0

預先介紹Ruby2.0是一個好的機會去回顧如何精確的用Ruby去樹立方法調用。

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

類層次結構

讓我們以基類的繼承這一經典的例子開始吧

  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'. 

在這個例子中,狗這個類繼承于動物類. 我們把動物類稱之為狗的超級類:

  1. Dog.superclass # => Animal 

記住這個方法 Dog#info 調用超級類,這個特殊的關鍵字執行了后面接著的這個層次的定義,像這個例子  Animal#info 這個類可以用繼承類的屬性

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

繼承類不以Animal結尾時很令人感興趣的地方

  1. Animal.superclass # => Object 

這個Animal類的申明相當于之前寫了一個Animal類的對象

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

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

因此怎么引出內核和基本對象呢?待會我將回談到內核,事實上并不會說太多的基本對象之外的東西只有有限數量的方法并且會以所有類的層次結構收尾。

  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只支持單根繼承(也就是說,一個類只有一個超類),但它支持 mixins. mixin是一組可以包含到其他類的方法。在Ruby,實現為Module類:

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

要在我們的Dog類中加入這個功能,我們可以用include 或者 prepend. 它們會插入這個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, ...] 

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

你可以隨意包含任意多個 include 和 prepend 的module。module還可以include和 prepende 其他module。當你不確定module和類得繼承體系時,馬上調用ancestors搞清楚。

單件類

在Ruby里, 在module和類得體系中,只有一個額外的層。任意對象可以有一個特殊的類優先于任何事:單件類(singleton class)

下面有個例子:

  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'. 

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

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

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

單件類是個真正的類,可以通過調用singleton_class來訪問:

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

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

這聽起來有些瘋狂...那不是需要無數個單件類啊?某種意義上講,是的,但是Ruby會在他們需要的時候再去創建。

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

  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 

單件類的名字來源于,他們有且只能有一個實例:

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

因為同樣的原因,你不能直接繼承一個單件類:

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

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

對于對象;來說,我們有:

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

對于類來說,Ruby會自動設置超類,所以穿越超類或者單點類的不同路徑都相等:

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

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

為了徹底搞暈大家,我***寫下個extend的注解。它可以看做在被擴展對象的單件類include一個module的簡寫3:

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

Ruby's 單件類遵從 eigenclass model.

方法查找和方法缺失

差不多都講完了!

Ruby支持的豐富的被繼承鏈是所有方法查找的基礎。

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

  1. lassie.woof # => NoMethodError: undefined method  
  2.   # `woof' for #<Dog:0x00000100a197e8 @name="Lassie">  
  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!" 

在上面的例子,當方法名是動物弄出來的噪音的一部分,我們調用make_noise,否則我們調用超類。超類會繼續向祖先查找知道到達BasicObject#method_missing,然后扔出NoMethodError 異常。

#p#

總結

總結一下,在Ruby中,當調用receiver.message 將會發生:

·沿著 receiver.singleton_class' 祖先鏈發送消息。

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

在其中,***個找到的方法執行,并返回結果。任何對父類的調用重新恢復查找過程,找第二次符合的方法。

一個Module mod的祖先鏈是:

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

·mod 它自己

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

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

我們可以把上面的過程寫成偽碼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 

寫出實際的查找過程更復雜,但看起來大致像:

  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 

技術注腳

1 mixin有一些限制:

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

·包含子模塊在模塊 M 不會影響之前包含模塊M的類,但是會影響之后包含模塊M的類。 請看這里.

·而且,Ruby 不允許祖先鏈包含循環。

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

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

作為經驗,立即數不能有單件類. 因為(1 << 42).class 是Fixnum 如果平臺是64位,否則是Bignum,對于Bignum也同樣適用。同樣的Ruby2.0后對于Float也同樣適用,因為一些浮點數也可能是立即數.

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

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

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

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

責任編輯:張偉 來源: oschina
相關推薦

2013-02-26 09:36:57

RubyRuby 2.0

2013-02-25 14:02:07

RubyWeb

2011-10-28 10:21:57

Ruby

2022-08-25 08:00:00

授權框架OAuth 2.0服務器

2009-12-17 13:23:25

Ruby eval方法

2009-12-17 11:36:55

Ruby輸入輸出

2009-12-16 17:00:43

Ruby on Rai

2013-02-26 09:42:09

RailsRuby

2017-09-30 09:10:21

Java重寫變量

2024-05-23 08:02:23

2009-12-14 17:48:46

Ruby String

2010-09-02 13:03:38

CSS垂直居中

2009-08-05 18:34:07

堆棧遍歷

2009-09-08 13:52:54

CheckBox選中

2019-01-28 08:50:09

線程安全

2010-09-10 13:58:38

DIV圖片居中

2024-01-08 08:45:07

Spring容器Bean

2022-04-10 23:42:33

MySQLSQL數據庫

2009-12-14 16:44:56

Ruby調用DLL

2009-12-17 11:27:31

Ruby時間方法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: av一区二区三区四区 | 成人欧美一区二区三区在线播放 | 欧美福利| 中文字幕精品一区 | 免费观看a级毛片在线播放 黄网站免费入口 | 最新黄色在线观看 | 密桃av| 国产福利视频 | 日韩在线免费电影 | 日韩欧美亚洲一区 | a免费在线 | 精品国产乱码久久久久久88av | 草久久久 | 成人精品一区二区三区 | 午夜av成人| 欧美精品一区二区三区蜜桃视频 | www.精品国产| 欧美成人一区二免费视频软件 | 成人av鲁丝片一区二区小说 | 激情在线视频 | 成人在线精品视频 | 精品少妇一区二区三区在线播放 | 欧美日韩在线视频一区 | 午夜不卡一区二区 | 国产有码 | 午夜午夜精品一区二区三区文 | 精品一区久久 | 久久com | 国产日韩在线观看一区 | 国产精品一区网站 | 亚洲国产精品视频一区 | 日韩av啪啪网站大全免费观看 | 一二三四在线视频观看社区 | 一级特黄a大片 | 狠狠干天天干 | 国产原创在线观看 | 一区二区三区小视频 | 韩国理论电影在线 | 久久久tv| 日韩精品激情 | 一级a爱片性色毛片免费 |