本節書摘來自華章出版社《effective ruby:改善ruby程式的48條建議》一書中的第1章,第1.2節,作者[美]彼得 j.瓊斯(peter j. jones),更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
運作的ruby程式中的每個對象都源自同一個類,即以某種方式繼承自類basicobject。試想這一個個互相關聯的對象是怎樣以basicobject為根節點構成一個熟悉的屬性圖的。在實踐中,這意味着一個類的對象能夠被另一個類的對象替換(感謝多态)。這就是我們能将一個行為類似數組卻又不真的是數組的對象傳遞給一個以array對象為預期參數的方法的原因。ruby程式員喜歡稱之為“鴨子類型”(duck typing)。與其要求對象是某個給定類的執行個體,不如将注意力放在該對象能做什麼上;換句話說,接口高于類型。用ruby的術語來說,鴨子類型意味着,相比is_a?方法你更喜歡使用respond_to?方法。
不過實際中很少見到有方法通過使用respond_to?進行參數檢查來保證其使用正确的接口。作為替代,我們更傾向于直接調用對象的方法,在對象沒有該方法時,讓ruby自己在運作時觸發nomethoderror異常。表面上看,這似乎給ruby程式員帶來了真正的問題。好吧,是這樣的,隻你我二人知道。這也是測試如此重要的原因。沒有什麼會阻止你意外地将time類型對象傳遞給接收date對象的方法。我們需要通過優秀的測試挑出各種各樣的錯誤。感謝測試,這些類型的問題是可以通過測試避免的。但即使這樣,這些多态替換也可能使經過測試的應用程式出現問題:

當你調用一個對象的方法而其傳回值剛好是讨厭的nil對象時,這種情況就會發生……nil是類nilclass的唯一對象。這樣的錯誤會悄然逃過測試而僅在生産環境下出現:如果一個使用者做了些超乎尋常的事情。另一種導緻該結果的情況是,當一個方法傳回nil并将其作為參數直接傳給另一個方法時。事實上存在數量驚人的方式可以将nil意外地引入你運作中的程式。最好的防範方式是:假設任何對象都可以為nil,包括方法參數和調用方法的傳回值。
避免在nil對象上調用方法的最簡單的方式是使用nil?方法。如果方法接收者(receiver)是nil,該方法将傳回真值,否則傳回假值。當然,nil對象在boolean上下文中總是假值,是以if和unless表達式可以如你所期望的那樣工作。以下幾行代碼是等
價的:
将變量顯式轉換為期望的類型常常比時刻擔心其為nil要容易得多。尤其是在一個方法即使是部分輸入為nil時也應該産生結果的時候。object類定義了幾種轉換方法,它們能在這種情況下派上用場。比如,to_s方法會将方法接收者轉化為string:
如你所見,nilclass#to_s傳回一個空字元串。使to_s如此之棒的原因是string#
to_s方法隻是簡單傳回self而不做任何轉換和複制。如果一個變量是string,那麼調用to_s的開銷最小。但如果變量期待string而恰好得到nil,to_s能幫你扭轉局面。作為例子,假設一個方法期待其參數之一為string,使用to_s,你可以避免參數為nil産生的
問題:
有趣的事情還在發生。如你所願,對幾乎所有的内置類(built-in classes)來說都存在一個比對轉換方法。這裡有一些适用于nil的最有用的例子。
當需要同時考慮多個值時,你可以使用類array提供的優雅的讨巧方式。array#compact方法傳回去掉所有nil元素的方法接收者的副本。這在将一組可能為nil的變量組裝成string時很常用。比如,如果一個人的名字由f?irst、middle和last組成(其中任何一個都可能為nil),那麼你可以用下面的代碼組成這個名字:
nil對象的嗜好是在你不經意間偷偷溜進正在運作的程式中。無論它來自使用者輸入、無限制資料庫,還是用nil來表示失敗的方法,意味着每個變量都可能為nil。
要點回顧
根據ruby的類型系統的運作方式,任何對象都可以為nil。
如果方法接收者是nil,nil?方法傳回真值,反之為假。
在适合的時候使用轉換方法,如to_s和to_i,可以将nil對象強制轉換為你期待的類型。
array#compact方法傳回去除所有nil元素的接收者的副本。