2009-11-11 53 views
5

have a class它公開了一個字符串值和一個int值(分別爲一個指令輸出並退出代碼)實現to_int和to_str的。除了通過to_sto_i揭露他們,我還使用to_strto_int,像這樣:後果在紅寶石

class Status 
    def to_s 
    @output 
    end 
    alias :to_str :to_s 

    def to_i 
    @status.exitstatus 
    end 
    alias :to_int :to_i 
end 

我這背後的想法是能夠在儘可能多的情況下,儘可能使用這個對象。讓它可以被一個字符串或int強制增加可用性。舉例來說,我可以用字符串拼接對象:

a_string = "Output was: " + results 

(我想用這個作爲INT脅迫,但Fixnum對象的例子+不喜歡它,所以它實際上並沒有正常工作: )

an_int = 1 + results 

一切到目前爲止我讀過曾表示,這可能是一個「壞」的事情。常見主題如下所示:「只有當對象基本上是一個字符串/ int」時,才能將對象表示爲字符串/ int,但使用to_s/to_i

毫無疑問,我的課不是「根本」的字符串或int。然而, 我有這個規則的一些問題:

  1. 它使我的班較不靈活/可用。例如:如果我沒有Status.to_str,我不能使用String。+連接Status輸出和另一個字符串。
  2. 這似乎違反了鴨子打字的精神。一個對象(即:即得到它作爲一個參數的方法)的用戶不應該關心什麼對象,它應該只關心什麼可以做。 (在這種情況下,「做」是指「可被表示爲一個串/ INT」。)
  3. 爲參數「基本上是一個串/ INT」是相當模糊我。例如,您會看到Float.to_int被提及很多。故事情節是,由於浮點數始終有一個整數部分,所以to_int是一個有效的方法。然而,我認爲這是虛假的:浮點數是而不是整數(因爲它有一個非整數部分),所以試圖將它們的「類型」等同起來沒有多大意義。你可以合法地轉換一個浮點整數(通過截斷),但我可以說,我可以我的狀態轉換爲整數,以及(通過「截斷」的所有非出口的代碼信息)。

所以,我的問題是:有沒有真正的(即:實際)實施to_strto_int危害


更新:JörgW Mittag給了我一個讓我想到什麼的例子。重新表述的問題是:是否真的需要有to_str/to_int當你已經有to_s/to_i? (除了特定方法已經預期to_str超過to_s的事實)

例如,在Jörg的陣列中。連接示例,數組成員通過to_s轉換,而分隔符通過to_str轉換。但這真的有必要嗎?如果Array.join改爲調用separator.to_s,那麼您可以成功傳遞更多的對象(例如:整數,符號等)並獲得更大的靈活性。 Ruby是否受益於這種分離?

回答

4

鴨子打字的精神當然不會有人查找Status對象的源代碼來找出返回的內容。

我個人認爲你應該通過兩個實例方法暴露文本結果和退出狀態:

class Status 

    ... 

    def message 
    @output 
    end 

    def exit_status 
    @status.exitstatus 
    end 

end 

然後如下

a_string = "Output was: " + results.message 
a_int = 1 + results.exit_status 

這立即有意義的任何人讀取使用代碼,恕我直言。

+0

我在實際的代碼中做了這些(請參閱鏈接的類),但爲了簡潔起見,我在這裏發佈的示例代碼中省略了這些方法。 – 2009-11-11 21:29:18

8

它使我的班級變得更加靈活/可用。例如:如果我沒有Status#to_str,我不能使用String#+連接狀態輸出和另一個字符串。

這是一個不好的例子,因爲連接字符串是單向的Ruby。字符串插值的首選方式:

a_string = "Output was: #{results}" 

只是工作 ™,因爲串插實際上是在插值表達式的結果調用to_s

這似乎違反了鴨打字的精神。一個對象(即:即得到它作爲一個參數的方法)的用戶不應該關心什麼對象,它應該只關心什麼可以做。 (在這種情況下,「do」的意思是「可以表示爲一個字符串/ int」)。

我認爲「可以表示爲字符串/ int」並不是真正的行爲。 IOW:「對象能做什麼」是關於某個上下文中有趣的行爲,「可以表示爲一個字符串/ int」並不是真正有趣的行爲。

如果你說「狀態IS-A整數」(基本上就是to_int的含義),那麼你就可以用它來做算術運算。但是,它甚至是什麼意思以「添加42到文件未找到」?成功的對數是什麼?失敗的平方根是多少?

在上面的字符串插值示例中,有趣的行爲是「可以顯示」。這基本上通過執行#to_s來表示。連接兩個字符串OTOH需要兩個字符串。

「基本上是字符串/整數」的參數對我來說很模糊。例如,您會看到Float#to_int被提及很多。故事情節是,由於浮點數始終有一個整數部分,所以to_int是一個有效的方法。然而,我認爲這是虛假的:浮點數是而不是整數(因爲它有一個非整數部分),所以試圖將它們的「類型」等同起來沒有多大意義。你可以合法地轉換一個浮點整數(通過截斷),但我可以說,我可以我的狀態轉換爲整數,以及(通過「截斷」的所有非出口的代碼信息)。

再次,這是一個相當弱的論點,因爲我實際上同意你的看法:那是錯誤的。

在德國法律中,我們有一個難以理解和不可原諒的原則,但我認爲這在這裏完全適用。它被稱爲「Keine Gleichheit im Unrecht」(錯誤中不平等)。這意味着憲法賦予的Equaliy的基本權利僅適用於法律範圍內的。換句話說:OJ不會使謀殺成爲合法的。

所以,僅僅因爲有垃圾代碼在Ruby核心庫(相信我,有很多),並不意味着你寫廢話,太:-)

在這特殊情況下,Float#to_int只是錯誤的,不應該存在。 Float不是Integer的子類型。乍一看,情況正好相反,即Integer#to_float是有效的,但實際上並非如此:在Ruby中,Integer s具有任意精度,但Float s具有固定精度。它有效實施Fixnum#to_float,但這是一個壞主意,因爲Integer s可以神奇地從Fixnum轉換爲BigInteger並回來,因此#to_float方法會「神奇地」出現和消失。

該最後幫助理解上的差異​​和to_xyz之間是Array#join的事情:它打印出數組的元素,通過隔離物分隔開。它通過在數組的每個元素上調用to_s並在分隔符上調用to_str來完成。一旦你明白了爲什麼它在一個上叫to_s而在另一個上叫to_str,你基本上就是這樣設置的。

(雖然你對Float#to_int意見已經表明您理解。)


邊注:在代數方面雙重分派,紅寶石實際使用#coerce協議。因此,如果您想要1 + a_status示例正常工作,則需要實施Status#coerce。但是,請不要。

+0

同意字符串插值是實踐中更好的方法;我只使用字符串concat作爲需要to_str的示例。 (實際上,在實際編碼中,我避免了串​​聯,因爲它*不能與任意對象一起工作)。 – 2009-11-12 03:16:28

+0

那麼爲什麼'Array#join'在一個上調用'to_s'而在另一個上調用'to_str'? – 2013-03-07 04:45:19

+0

我的猜測是,連接的項目不應該是字符串 - 我們想要加入的是他們的字符串表示。 OTOH分隔符應該是一個字符串,而不是任何對象。寫作'[1,2]。join(3)'是一個錯誤,在分隔符上使用to_str是檢測它的方法。 – 2014-10-28 12:51:01