Ruby中的to_s与to_str(以及to_i/to_a/to_h与to_int/to_ary/to_hash)

Jef*_*rey 64 ruby string methods

我正在学习Ruby,而且我已经看到了一些令我困惑的方法,特别是to_svs to_str(以及to_i/ to_int,to_a/ to_ary,&to_h/ to_hash).我读过的内容解释了较短的形式(例如to_s)用于显式转换,而较长的形式用于隐式转换.

我真的不明白to_str将如何使用.除了String以外的东西会定义to_str吗?你能为这种方法提供实际应用吗?

And*_*all 77

首先请注意,所有这些都适用于Ruby中的每对"短"(例如to_s/ to_i/ to_a/ to_h)与"long"(例如to_str/ to_int/ to_ary/ to_hash)强制方法(对于它们各自的类型),因为它们都具有相同的语义.


它们有不同的含义.你不应该执行to_str,除非你的对象的行为就像一个字符串,而不是仅仅是表示的一个字符串.实现的唯一核心类to_str是String本身.

来自Programming Ruby(引自这篇博文,值得一读):

[ to_ito_s]并不是特别严格:例如,如果某个对象具有某种正常的表示形式,那么它可能会有一个to_s方法...... [ to_intto_str]是严格的转换函数:只有当[你的]对象能够自然地实现它们时才能实现它们每个地方都可以使用字符串或整数.

来自Pickaxe的旧Ruby文档有这样的说法:

to_s几乎所有类都支持的不同,to_str通常只由那些充当字符串的类实现.

例如,除了Integer之外,FloatNumeric都实现to_int(to_i相当于to_str),因为它们都可以很容易地替换整数(它们实际上都是数字).除非你的类与String有类似的紧密关系,否则你不应该实现to_str.

  • 安德鲁,谢谢.但实际上,这意味着什么"那些像字符串一样的类?" 这是否意味着他们实现与字符串相同的方法?如果对象已经像字符串一样运行,那么to_str还会返回除self之外还有什么? (7认同)
  • @JeffStorey除非你创建一个类似String的类,并且至少实现它所做的所有方法,否则不行.当然,在这种情况下,你可能会有子类String,并免费获得它.这样做的一个很好的例子是Ruby的数字:Float,Integer和Numeric都实现了`to_int`(`to_i`的"to_str`"等价物),因为它们可以很容易地互相替换. (4认同)
  • 查看Ruby koans _about_to_str_示例以获得更多信息. (2认同)

Eld*_*rum 20

要了解是否应该使用/实现to_s/ to_str,让我们看一些例子.当这些方法失败时,要考虑这一点.

1.to_s              # returns "1"
Object.new.to_s     # returns "#<Object:0x4932990>"
1.to_str            # raises NoMethodError
Object.new.to_str   # raises NoMethodError
Run Code Online (Sandbox Code Playgroud)

我们可以看到,to_s很高兴将任何对象转换为字符串.另一方面,当其参数看起来不像字符串时to_str 引发错误.


现在让我们来看看Array#join.

[1,2].join(',')     # returns "1,2"
[1,2].join(3)       # fails, the argument does not look like a valid separator.
Run Code Online (Sandbox Code Playgroud)

Array#join在加入数组中之前将它们转换为字符串(无论它们是什么)都是很有用的,因此Array#join调用to_s它们.

但是,分隔符应该是一个字符串 - 有人调用[1,2].join(3)可能会犯错误.这就是Array#join调用to_str分隔符的原因.


同样的原则似乎适用于其他方法.考虑to_a/ to_aryon hash:

{1,2}.to_a      # returns [[1, 2]], an array that describes the hash
{1,2}.to_ary    # fails, because a hash is not really an array.
Run Code Online (Sandbox Code Playgroud)

总之,这是我如何看待它:

  • 调用to_s 以获取描述该对象的字符串.
  • 调用to_str以验证对象是否真的像字符串一样.
  • to_s在构建描述对象的字符串时实现.
  • to_str当您的对象完全像字符串一样运行时实现.

我认为你可以实现to_str自己的情况可能是一个ColoredString类 - 一个附加了颜色的字符串.如果它似乎昭示着你,传递一个彩色逗号join是不是一个错误,并且会导致"1,2"(即使该字符串不会被着色),然后落实to_str上ColoredString.