Ruby中to_s和to_str、to_i和to_int、to_a和to_ary、to_h和to_hash的解釋說明

包括to_sto_strto_ito_intto_ato_aryto_hto_hash。統稱爲to_xto_xxx程序員

那麼,to_xto_xxx的區別是什麼,何時使用to_x,何時使用to_xxx數組

解釋

使用鴨子模型來解釋比較容易點。安全

只要像鴨子,就能當成鴨子,這就是to_x。只有它真的是鴨子,才能當成鴨子,這就是to_xxxruby

to_sto_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_strblog

>> 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_xxxci

to_ito_intto_ato_aryto_hto_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_ato_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_ito_int都定義了。

>> a=3.5
>> a.class   # => Float

>> a.to_i    # => 3
>> a.to_int  # => 3

結論

分爲兩種狀況:何時調用to_xto_xxx,以及何時在本身的類中實現to_xto_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

相關文章
相關標籤/搜索