昨天在看web敏捷開發之道的時候看到class << self這樣的語法,一會兒弄蒙了,丫的這是什麼語法阿。呆了,徹底看不懂。後來經查google才知道是單態方法——singleton_method java
關於class << self,有一篇比較好的博文,請見:http://www.devalot.com/articles/2008/09/ruby-singleton web
定義singleton_methods有三種方式 編程
第一種: 直接給對象打開定義 ruby
這是最簡單相信也是見得最多的一種方式: 函數
- a = Array.new
-
- def a.size
- "Hello World!"
- end
輸入puts a.size ====>輸出"Hello,World",而不是0
咱們知道ruby比較有特色的一個地方是,在任什麼時候間任何地點,能夠對一個類或對象打開進行添加方法或者重寫方法。 post
但這是爲何呢?不知道讀者有沒有想過這個問題。從靜態語言的角度,好比java或者C++,我麼知道只能在一個類的範圍內添加方法。學過彙編的朋友知道,方法自己是內存中的一段指令而已。只不過把一些傳參或者返回之放在指定的寄存器上。而ruby底層是用C寫的。C++和java中的類本質跟C中的結構體也沒有什麼區別,術語多態和回調只不過是在指定的方法表(每一個java類字節碼都有一個方法表)入口處放置實際C的函數指針。 google
通過上面的分析,是否是意味着ruby類的開放性也是基於類的呢? spa
查過google以後,發覺分析對了。原來ruby在任何地方能對一個既存的對象打開也是基於類的,只不過是個匿名的內部類而已,而這個類繼承於當前實例的類。 .net
因此,在上面的代碼中,咱們徹底能夠調用super方法調用父類的相應函數。如 指針
- a = Array.new
-
- def a.size
- puts super
- "Hello World!"
- end
puts a.size ======> 輸出
0
"Hello,World"
說明咱們理解沒有誤差。
這樣,咱們對於第二種方式也就不難理解了。
第二種:使用"<<"方式
上面的代碼還能夠這樣寫:
- a = Array.new
-
-
- class << a
- def size
- puts super
- "Hello,World"
- end
- end
-
- puts a.size =======>
- 0
- "Hello,World"
-
- b = Array.new
- puts b.size =========>
- 0
很顯然,第二種方式比較能體現本質(某一個類繼承於a,而後重寫size這個方法)
第三種方式,經過instance_eval
- a = Array.new
-
- a.instance_eval <<EOF
- def size
- puts super
- puts "Hello,World!"
- end
- EOF
-
- <strong>b = Array.new
-
-
- a.size =======>
-
- 0
-
- "Hello,World"
-
- b.size ====>
-
- 0</strong>
雖然明白instance_eval是singleton_method方式的一種,可是由於是第一次見instance_eval,因而google之,發現原來這玩意兒和class_eval很類似。因而又google class_eval.
因而,又發現一篇比較好的博文:http://www.jimmycuadra.com/posts/metaprogramming-ruby-class-eval-and-instance-eval
博文中說道,class_module是從Module中獲得的,因此class_module的接受者必須是個類,好比說
- a=Array.new
- a.class_eval 這樣是錯的,會報找不到class_eval這個方法
-
- 應該是Array.class_eval才能夠
而咱們知道在混合編程(mix)中,include 某個Module時,該Module的全部實例方法只能由子類的實例所調用(至關於多了繼承於Module),故class_eval定義以後,只能是Array的全部的實例調用,Array本身調用會出錯(確定的,假如Array本身調用不出錯的話,這個方法就是靜態方法了)
- a=Array.new
-
- Array.class_eval do
- def hint
- "hello"
- end
- end
-
- puts a,hint 輸出hello
- b = Array.new
- puts b.hint 輸出hello
-
- puts A.hint 出錯,沒有找到這個方法
ruby是徹底面向對象的,即便對於某個實際的類也是如此。ruby的任何類,好比Array,或者是任何本身定義的類,都是Class類的實例。因此,類的靜態方法,至關於這個類(或者是Class類的對象)的singleton_methods.也就是說,ruby本質是沒有靜態方法的。
基於此,也就很天然的明白instance_eval了。
好比,我像下面這樣定義
- a=Array.new
- a.instance_eval do
- def hint
- "hello"
- end
- end
-
- puts a.hint 輸出hello
- b=Array.new
- puts b.hint 報錯,沒有找到此方法
-
- 假如我像下面這樣定義:
- Array.instance_eval do
- def hint
- "hello"
- end
- end
-
- 本質上至關於這樣的代碼:
- class Array
- def self.hint
- "hello"
- end
- end
-
- 固然,也能夠是這樣
- class Array
- class << self
- def hint
- "hello"
- end
- end
- end
-
- <strong><span style="color:#660000;">不過ruby對靜態代碼的限制比較強,不像java,實例能夠調用靜態方法,在ruby中,靜態方法只能是類調用,由於ruby本質是沒有靜態方法的,只有實例方法。只有所屬的對象才能調用本身的
- 方法,這也間接地說明了ruby是一種徹底的面嚮對象語言。</span></strong>