在Ruby中to_s与to_str(to_i / to_a / to_h与to_int / to_ary / to_hash)

我正在学习Ruby,并且我看到了一些让我困惑的方法,特别是to_s vs to_str (以及类似to_i / to_intto_a / to_aryto_h / to_hash )。 我读过的内容解释说,较短的格式(例如to_s )用于显式转换,而较长的格式用于隐式转换。

我真的不明白如何to_str实际上会被使用。 除了string以外的东西会定义to_str吗? 你能给这个方法的实际应用吗?

注意,所有这些都适用于to_s每一对“short”(例如to_s / to_i / to_a / to_h )和“long”(例如to_str / to_int / to_ary / to_hash )强制方法(分别为它们的types)他们都有相同的语义。


他们有不同的含义。 你不应该实现to_str除非你的对象像一个string一样,而不是只能被一个string表示 。 唯一实现to_str核心类是String本身。

编程ruby (引自这篇博文 ,这是值得一读的):

[ to_ito_s ]并不是特别严格:如果一个对象具有某种forms的表示forms作为string,例如,它可能会有一个to_s方法… [ to_intto_str ]是严格的转换函数:只有在[你的]对象可以自然地在每个地方使用一个string或一个整数可以被使用。

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

与几乎所有类都支持的to_s不同, to_str通常只能由像string那样的类来实现。

例如,除了Integer , Float和Numeric都实现to_intto_i相当于to_str ),因为它们都可以很容易地替代Integer(它们实际上都是数字)。 除非你的类与String有类似的紧密关系,否则你不应该实现to_str

要了解是否应该使用/实现to_s / to_str ,我们来看一些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 

正如我们所看到的, to_s很乐意把任何对象变成一个string。 另一方面, to_str在参数看起来不像string时会产生错误


现在让我们看看Array#join

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

在joinArray#join之前, Array#join将数组中的项(不pipe它们是真实的)转换成string是很有用的,所以Array#join对它们的调用to_s

但是,分隔符应该是一个string – 有人调用[1,2].join(3)可能会犯一个错误 。 这就是为什么Array#join在分隔符上Array#join调用to_str的原因。


其他方法似乎也适用同样的原则。 考虑哈希上的to_a / to_ary

 {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. 

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

  • 调用to_s来获取描述对象的string。
  • 调用to_str来validation一个对象真的像一个string。
  • 实现to_s当你可以build立一个描述你的对象的string。
  • 当你的对象完全像string一样行为的时候实现to_str

我认为你可以自己实现to_str情况也许是一个ColoredString类 – 一个附加了颜色的string。 如果你很清楚传递一个彩色的逗号并不是错误,并且应该导致"1,2" (即使该string不会被着色),那么 to_str上执行to_str。