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_xxx

to_sto_str為例。

所有對象都能使用to_s方法,用來將對象以字符串的格式去描述、去輸出。也就是說,所有對象都能使用字符串的描述格式。

# 任意對象都能直接使用to_s()去描述自身
>> Object.new.to_s
=> "#<Object:0x00000002272e58>"

# 數值類中重寫了to_s(),使之轉換成字符串格式的數值描述形式
>> 1.to_s
=> "1"

只有真的是字符串的對象,或者能完全扮演字符串的對象,才有必要去使用to_str。例如,String類自身、String類的某些子類,它們是真的鴨子,並不是簡單的像鴨子。也就是說,只有嚴格符合鴨子要求的類型,才可以考慮去定義to_str

再嚴格一點,當某個地方能使用String類對象的時候,也一定能使用某類對象時(比如String的部分子類),這類對象就可以考慮去使用to_str

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM