Ruby對象模型淺析

1.橫向查找

今天主要簡單講講Ruby對象模型,說簡單它也是比較簡單的--只要知道在Ruby里面一切都是對象。說難,它確實跟其他語言有那么點不一樣。這里簡單講講,我們看下面的代碼。

[1] pry(main)> a = "lanzhiheng"
=> "lanzhiheng"
[2] pry(main)> a.class
=> String
[3] pry(main)> a.class.class
=> Class
[4] pry(main)> a.class.class.class
=> Class

這堆語法應該很熟悉吧。這里我創建一個字符串"lanzhiheng"并賦值給a。這里aString類型的一個實例。而String類型又是Class類型的一個實例,用中文說就是類類型的一個實例。而類類型又是類類型的一個實例。所以類類型(Class類型)應該是"最原始"的類型了。我們姑且把這種方式稱作橫向查找。我們通過每個對象的class屬性來找到它所屬的類型。

2.縱向查找

有橫向查找當然就會有縱向查找,Ruby中我們通過superclass屬性來查找一個類的父類,我們可以看下面這個運行結果。

[18] pry(main)> a = "lanzhiheng"
=> "lanzhiheng"
[19] pry(main)> a.superclass
NoMethodError: undefined method `superclass' for "lanzhiheng":String
from (pry):19:in `__pry__'
[20] pry(main)> a.class
=> String
[21] pry(main)> a.class.superclass
=> Object
[22] pry(main)> a.class.superclass.superclass
=> BasicObject
[23] pry(main)> a.class.superclass.superclass.superclass
=> nil

這個訪問鏈是不是很熟悉?由于a只是一個普通的對象,它沒有父類所以這里通過訪問它的superclass屬性會報錯。然后我們通過繼承鏈訪問String的父類。發現結果是這樣的String -> Object -> BasicObject。好了,到這里就好了。因為這個BaseObject是最基本的類了,所有的類都繼承自它。不過開發里面用得比較多的還是Object類,它包含的基本方法比BasicObject要多得多。這種尋找父類的方式我們姑且叫做縱向查找。一步一步向上搜索它的祖先。

難道要獲取一個對象的祖先鏈就必須要這樣嗎?當然不是,肯定有更簡單的辦法。

[34] pry(main)> a.class.ancestors
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]

這個可以獲取所有的String類型的祖先類(包括它自己)。但是不對啊,明顯多了一些東西!!!多出來的東西叫做Module。可以用于類的擴展,Ruby On Rails這個框架里面就用了很多這種東西。不過今天討論的是類,這里先不多說。因為模塊并不是我們所需要的類類型。所以我們可以這樣把它去掉。

[35] pry(main)> a.class.ancestors.select {|item| item.is_a?(Class) }
=> [String, Object, BasicObject]

我們通過獲取到祖先后,通過select來篩選掉不需要的Module。其實這只是權宜之計,不妨再多說一點:

[38] pry(main)> Class.superclass
=> Module
[40] pry(main)> Module.class
=> Class

其實Module類是類類型的父類,而Module同時又是類類型的實例。這是個比較古怪的事情。不過這說明我們不能以同樣的方法來篩選Module

[41] pry(main)> a.class.ancestors.select {|item| item.is_a?(Module) }
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]

String類型的整條祖先鏈其實都是Module。不過由于屬于Class卻不一定是Module所以我們姑且先這樣做著吧。

3.單件方法

傳統編程中如果我想給一個對象增加方法,我們的做法是在該方法所屬的類或者其父類中定義需要的方法。而在Ruby里面我們可以更簡單地完成這個事情。通過單件方法我們可以直接綁定方法在單個對象中。看看下面這個例子:

a = "hello lan"
b = "hello world"

def a.goodbye; "good bye" end

運行結果

[57] pry(main)> a.goodbye
=> "good bye"
[58] pry(main)> b.goodbye
NoMethodError: undefined method `goodbye' for "hello world":String
from (pry):58:in `__pry__'

可見這個方法只綁定在了對象a中,而在對象b中卻沒有它的身影。這在一定程度上增加了程序的靈活性。我們為一個對象增加方法不再需要重新定義類的行為,而只需要綁定在相關的對象上即可,過不過癮?

4. 單件類

上面這些知識對于一般的開發來說基本上已經夠用了。當然這里提到單件類是想表示一下Ruby跟其他語言有些不同的地方。單件類也是類,只不過默認情況下Ruby把它隱藏起來了。
對于單件類,今天淺嘗一下,先看看它到底是什么

[62] pry(main)> a.singleton_class
=> #<Class:#<String:0x007fad3cd46cc8>>
[63] pry(main)> a.singleton_class.instance_methods.grep /good/
=> [:goodbye]
[64] pry(main)> a.singleton_class.class
=> Class

從上面可以看出單件類其實真的是一個類,雖然在繼承鏈中沒有給出來,但是,它確實是一個類。而且我們定義的單件方法goodbye其實就是這個類中的實例方法。只是這個類的實例只有一個就是對象a,因此就只有它能夠訪問這個方法了。而且我們貌似不能通過單件類來創建新的對象:

[70] pry(main)> k = a.singleton_class.new
TypeError: can't create instance of singleton class
from (pry):70:in `new'

我們就是通過定義單件類的實例方法來把方法綁定到了單件類對應的對象中去的。這是我覺得Ruby相當不錯的特性。

今天就到這吧。

Happy Coding !! _

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,915評論 18 139
  • ruby面向對象初步理解 類與對象無疑是ruby的核心,可能最開始看上去有一點困惑,似乎有太多的概念:類、對象、類...
    感覺被掏空閱讀 1,206評論 0 3
  • 最近復習了下 ruby 對象模型的知識,參照了 Ruby Metaprogramming,于是邊看邊做筆記,還是收...
    張羽辰閱讀 539評論 0 4
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 被操控的社會 … 當!!被操控 當??被操控 ……… 最終思想被操控 世界好像變得如此美好 好像夢一般 縱使生活在...
    liuwqself閱讀 235評論 0 0