在Ruby中实现to_int和to_str的后果

I have a class公开了字符串值和int值(分别是命令输出退出代码).除了通过to_s和to_i公开它们之外,我还使用to_str和to_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时使用to_s / to_i,但只有当你的对象基本上是字符串/ int时才使用to_str / to_int”.

毫无疑问,我的课程不是“根本上”字符串或int.然而
我对此规则有一些问题:

>这使我的课程变得不那么灵活/可用.例如:我无法使用String.如果我没有Status.to_str,则将Status输出与另一个字符串连接.
>这似乎违反了鸭子打字的精神.对象的用户(即:将其作为参数获取方法)不应该关心该对象是什么,它应该只关心它能做什么. (在这种情况下,“do”表示“可以表示为字符串/ int”.)
>“基本上是一个字符串/ int”的参数对我来说非常模糊.例如,您将看到Float.to_int被大量提及.故事说,由于浮点数始终具有整数分量,因此to_int是一种有效的方法.但是,我认为这是假的:浮点数不是一个整数(因为它有一个非整数分量),所以试图将它们的“类型”等同起来没有多大意义.你可以合法地将Float转换为整数(通过截断),但我可以说我也可以将我的状态转换为整数(通过“截断”所有非退出代码信息).

所以,我的问题是:在实现to_str和to_int时是否有任何真实的(即:实际的)伤害?

更新:JörgWMittag举了一个例子让我想到了什么.重新解释这个问题:当你已经拥有to_s / to_i时,真的需要有to_str / to_int吗? (除了特定方法已经期望to_str超过to_s的事实)

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

解决方法

It makes my class less flexible/usable. For example: I Couldn’t use String#+ to concatenate the Status output with the other string if I didn’t have Status#to_str.

这是一个不好的例子,因为连接字符串是单一的Ruby.字符串插值是首选方式:

a_string = "Output was: #{results}"

这只是工作™,因为字符串插值实际上调用插值表达式的结果上的to_s.

It seems to violate the spirit of duck-typing. The user of an object (ie: a method that gets it as a parameter) shouldn’t care what that object is,it should only care what it can do. (In this case,“do” means “can be represented as a string/int”.)

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

如果你说“Status IS-A Integer”(这实际上是to_int的意思),那么你就可以对它进行算术运算.但它甚至意味着“添加42到文件未找到”?成功的对数是多少?失败的平方根是什么?

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

The arguments for “is fundamentally a string/int” are pretty fuzzy to me. For example,you’ll see that Float#to_int is mentioned a lot. The story goes that since a floating-point number always has an integer component,to_int is a valid method. However,I think this is spurIoUs: a Float is not an integer (as it has a non-integer component) and so trying to equate their “typeness” doesn’t make much sense. You can legitimately convert a Float to an integer (through truncation),but then I can say that I can convert my Status to an integer as well (by “truncating” all of the non-exit-code information).

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

在德国法律中,我们有一个难以掌握和非本能的原则,但我认为这完全适用于此.它被称为“Keine Gleichheit im Unrecht”(在错误中不平等).这意味着宪法赋予的Equaliy的基本权利仅适用于法律.换句话说:OJ不会使谋杀合法化.

所以,仅仅因为Ruby核心库中有垃圾代码(相信我,有很多),并不意味着你也可以写垃圾:-)

在这种特殊情况下,Float#to_int只是完全错误,不应该存在. Float不是Integer的子类型.乍一看,相反似乎是正确的,即Integer#to_float是有效的,但实际上并非如此:在Ruby中,整数具有任意精度,但Floats具有固定的精度.实现Fixnum#to_float是有效的,但这是一个坏主意,因为整数可以神奇地从Fixnum转换为BigInteger并返回,因此#to_float方法会“神奇地”出现并消失.

最后帮助我理解to_x和to_xyz之间区别的是Array#join:它打印出数组的元素,由分隔符对象分隔.它通过在数组的每个元素上调用to_s并在分隔符上调用to_str来完成此操作.一旦你理解为什么它在一个调用to_s而在另一个调用to_str,你基本上就已经设置了.

(虽然你对Float#to_int的评论已经表明你确实理解了.)

旁注:对于代数上下文中的双重调度,Ruby实际上使用#coerce协议.因此,如果您希望1 a_status示例有效,则需要实现Status#coerce.但是,请不要.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...