2009-11-11 51 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