在Ruby中实现to_int和to_str的后果

在Ruby中实现to_int和to_str的后果,ruby,duck-typing,Ruby,Duck Typing,I,它公开一个字符串值和一个int值(分别是命令输出和退出代码)。除了通过向_s和向_i公开它们之外,我还使用向_str和向_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可以提高可用

I,它公开一个字符串值和一个int值(分别是命令输出和退出代码)。除了通过
向_s
向_i
公开它们之外,我还使用
向_str
向_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.+不喜欢它,所以它实际上不起作用:)

到目前为止,我读到的所有东西都表明,这可能是一件“不好”的事情。常见的主题是这样的:“当对象可以表示为字符串/int时,使用
to_s
/
to_i
,但只有当对象基本上是字符串/int时才使用
to_str
/
to_int

毫无疑问,我的类“基本上”不是字符串或int 我对这条规则有一些问题:

  • 它使我的类不那么灵活/可用。例如:如果我没有Status.to_str,我无法使用String.+将状态输出与另一个字符串连接起来
  • 这似乎违背了鸭子打字的精神。对象的用户(即:将其作为参数获取的方法)不应该关心该对象是什么,而应该只关心它能做什么。(在本例中,“do”表示“可以表示为字符串/int”。)
  • “基本上是字符串/int”的参数对我来说非常模糊。例如,您将看到经常提到
    Float.to_int
    。故事是这样的,因为浮点数总是有一个整数分量,
    to_int
    是一个有效的方法。然而,我认为这是错误的:浮点不是整数(因为它有一个非整数成分),所以试图将它们的“类型”等同起来没有多大意义。您可以合法地将浮点转换为整数(通过截断),但我可以说我也可以将状态转换为整数(通过“截断”所有非退出代码信息)
  • 因此,我的问题是:在实现
    到str
    到int
    的过程中是否存在任何实际的(即:实际的)危害


    更新:Jörg W Mittag举了一个让我想到一些事情的例子。重新表述这个问题:当你已经有了
    /
    的时候,真的有必要有
    到_str
    /
    到_int
    ?(除了特定方法已经期望
    超过


    例如,在Jörg的Array.join示例中,数组成员通过转换为_s,而分隔符通过转换为_str。但是这真的是必要的吗?如果Array.join改为调用separator.to_,那么您可以成功地向它传递更多的对象(例如:整数、符号等),并获得更大的灵活性。Ruby会从这种分离中受益吗?

    duck类型的精神当然不会让人在源代码中查找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
    
    这对任何阅读代码的人来说都是有意义的,IMHO

    它使我的类不那么灵活/可用。例如:如果我没有
    Status#to_str
    ,我无法使用
    String++
    将状态输出与另一个字符串连接起来

    这是一个糟糕的例子,因为串接字符串是单向的Ruby。字符串插值是首选方法:

    a_string = "Output was: #{results}"
    
    这就行了™, 因为字符串插值实际上对插值表达式的结果调用

    这似乎违背了鸭子打字的精神。对象的用户(即:将其作为参数获取的方法)不应该关心该对象是什么,而应该只关心它能做什么。(在本例中,“do”表示“可以表示为字符串/int”。)

    我认为“可以表示为字符串/int”并不是真正的行为。IOW:“对象可以做什么”是关于特定上下文中有趣的行为,“可以表示为字符串/int”不是真正有趣的行为

    如果你说“Status IS-A Integer”(这本质上就是
    to_int
    的意思),那么你可以用它来做算术运算。但“将42添加到未找到的文件”意味着什么呢?成功的对数是多少?失败的平方根是多少

    在上面的字符串插值示例中,有趣的行为是“可以显示”。这基本上是通过实现
    #to_s
    来表示的。连接两个字符串OTOH需要两个字符串

    “基本上是字符串/int”的参数对我来说非常模糊。例如,您会看到经常提到
    Float#to_int
    。故事是这样的,因为浮点数总是有一个整数分量,
    to_int
    是一个有效的方法。然而,我认为这是错误的:浮点不是整数(因为它有一个非整数成分),所以试图将它们的“类型”等同起来没有多大意义。您可以合法地将浮点转换为整数(通过截断),但我可以说我也可以将状态转换为整数(通过“截断”所有非退出代码信息)

    同样,这是一个相当弱的论点,因为我实际上同意你的观点:那是错误的

    在德国法律中,我们有一项原则很难掌握,而且是非首创的,但我认为它在这里完全适用。它被称为“Keine Gleichheit im Unrecht”(错误中没有平等)。这意味着宪法赋予的基本平等权利只适用于法律。换句话说:OJ不会让谋杀合法化

    所以,就因为有垃圾代码
    a_string = "Output was: #{results}"