包括to_s
和to_str
、to_i
和to_int
、to_a
和to_ary
、to_h
和to_hash
。統稱爲to_x
和to_xxx
。程序員
那麼,to_x
和to_xxx
的區別是什麼,何時使用to_x
,何時使用to_xxx
。數組
使用鴨子模型來解釋比較容易點。安全
只要像鴨子,就能當成鴨子,這就是to_x
。只有它真的是鴨子,才能當成鴨子,這就是to_xxx
。ruby
以to_s
和to_str
爲例。設計
全部對象都能使用to_s
方法,用來將對象以字符串的格式去描述、去輸出。也就是說,全部對象都能使用字符串的描述格式。code
# 任意對象都能直接使用to_s()去描述自身 >> Object.new.to_s => "#<Object:0x00000002272e58>" # 數值類中重寫了to_s(),使之轉換成字符串格式的數值描述形式 >> 1.to_s => "1"
只有真的是字符串的對象,或者能徹底扮演字符串的對象,纔有必要去使用to_str
。例如,String類自身、String類的某些子類,它們是真的鴨子,並非簡單的像鴨子。也就是說,只有嚴格符合鴨子要求的類型,才能夠考慮去定義to_str
。對象
再嚴格一點,當某個地方能使用String類對象的時候,也必定能使用某類對象時(好比String的部分子類),這類對象就能夠考慮去使用to_str
。blog
>> 1.to_str NoMethodError: undefined method `to_str' for 1:Fixnum >> Object.new.to_str NoMethodError: undefined method `to_str' for #<Object:0x00000002267648>
或者說,to_x
是輸出出來給人讀的,to_xxx
是讓程序健壯的,讓你在不理解的狀況下別亂定義to_xxx
。ci
to_i
和to_int
、to_a
和to_ary
、to_h
和to_hash
也都同樣,to_x
是寬泛程度的數據類型轉換,to_xxx
是嚴格的、必須知道是幹什麼的時候才進行的數據類型轉換。字符串
例如:
>> [1, 2].join(',') => "1,2" >> [1, 2].join(1) TypeError: no implicit conversion of Fixnum into String
數組的join()
方法用來將數組轉換成字符串,且使用鏈接字符進行鏈接。也就是說,數組中的每一個元素以及鏈接符自身都得轉換成字符串,才能保證轉換的結果是字符串。
對於數組自身而言,調用to_s()
便可將其內全部元素轉換成字符串格式,可是鏈接符不能隨便轉換,只有那些可以做爲鏈接符的類型才能轉換,例如這裏的數值1不能做爲鏈接符,因此應當讓鏈接符的轉換過程使用to_str()
,保證程序的健壯性、安全性。固然,若是你認爲1也能夠做爲鏈接符,你能夠在設計join()程序的時候,經過to_s()
去轉換這裏的數值1,但關鍵是join()不是你寫的,而是別人寫的,別人這麼寫有他本身的考慮。
再例如to_a
和to_ary
,將hash結構轉換成array:
>> {a: 10}.to_a => [[:a, 10]] >> {a: 10}.to_ary NoMethodError: undefined method `to_ary' for {:a=>10}:Hash Did you mean? to_a
上面第一個轉換能成功。由於寫hash類型的程序員認爲,hash能夠以一種方式轉換成數組類型,因而它在hash類中定義了to_a()
。這個轉換並不影響大局,僅僅只是實現一個簡單的功能而已。
而to_ary()
轉換失敗,由於hash是hash,array是array,在能使用array的地方,不表明能使用hash,假如在hash中定義了to_ary
,那麼在很大意義上就意味着hash和array在不少地方能夠互換使用(特指hash能替代array),也就是能使用array的地方極可能也應該容許它使用hash。固然,僅僅只是意義上的替換,而非真正的能替換,但這極可能會牽一髮而動全身。
再例如,浮點數確定可使用to_i
簡單轉化成整數類型,但它應該定義to_int()
嗎?若是編寫Float類的程序員認爲,浮點數就是浮點數,毫不能當成int對象,那麼他就要保證float對象不能轉換成int,這時就不要定義to_int
。但若是他認爲浮點數做爲一種int使用,那麼就應該定義to_int
。事實上,Float類中to_i
和to_int
都定義了。
>> a=3.5 >> a.class # => Float >> a.to_i # => 3 >> a.to_int # => 3
分爲兩種狀況:何時調用to_x
和to_xxx
,以及何時在本身的類中實現to_x
和to_xxx
。
to_x
來將你的類作個寬鬆的類型轉換Cls.to_xxx(arg)
來驗證arg真的能充當Cls使用to_x
,只要你認爲能夠按照你的觀點轉換將你的類轉換成某個類型Cls.to_xxx(arg)
,只有當前想要保證某arg對象真的能夠充當Cls時定義最後,基本上全部類均可以按照你本身的想法去定義to_x
,可是不多定義to_xxx
,除非你真的知道本身在幹什麼,知道這會形成什麼結果。
參考連接:to_s vs. to_str (and to_i/to_a/to_h vs. to_int/to_ary/to_hash) in Ruby