我正在学习 Ruby,我看到了一些让我有点困惑的方法,尤其是to_s
vs to_str
(以及类似的to_i
/ to_int
、to_a
/ to_ary
、 & to_h
/ to_hash
)。我读过的内容解释了较短的形式(例如to_s
)用于显式转换,而较长的形式用于隐式转换。
我真的不明白如何to_str
实际使用。字符串以外的东西会定义to_str
吗?你能给出这个方法的实际应用吗?
首先请注意,所有这些都适用于 Ruby 中的每一对“短”(例如to_s
/ to_i
/ to_a
/ to_h
)与“长”(例如to_str
/ to_int
/ to_ary
/ to_hash
)强制方法(对于它们各自的类型),因为它们都具有相同的语义。
它们有不同的含义。你不应该实现to_str
,除非你的对象像一个字符串,而不是仅仅由一个字符串表示。唯一实现的核心类to_str
是 String 本身。
来自Programming Ruby(引自这篇博文,值得一读):
[
to_i
和to_s
] 不是特别严格:例如,如果一个对象具有某种体面的字符串表示形式,它可能会有一个to_s
方法…… [to_int
和to_str
] 是严格的转换函数:只有当 [您的] 对象可以自然地实现它们时,您才能实现它们在每个可以使用字符串或整数的地方使用。
Pickaxe 中较旧的 Ruby 文档有这样的说法:
几乎所有类都支持的不同
to_s
,to_str
通常仅由那些行为类似于字符串的类实现。
例如,除了Integer之外,Float和Numeric都实现了to_int
(to_i
的等价物to_str
),因为它们都可以很容易地替换 Integer (它们实际上都是数字)。除非你的类与 String 有同样紧密的关系,否则你不应该实现to_str
.
要了解您是否应该使用/实现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
正如我们所看到的,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.
Array#join
在加入它们之前将数组中的项目(无论它们实际上是什么)转换为字符串很有用,因此Array#join
调用to_s
它们。
但是,分隔符应该是一个字符串——有人打电话[1,2].join(3)
可能会出错。这就是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
以获取描述对象的字符串。to_str
来验证一个对象真的像一个字符串。to_s
当您可以构建一个描述您的对象的字符串时实现。to_str
当您的对象可以完全表现得像一个字符串时实现。我认为你可以to_str
自己实现的情况可能是一个ColoredString
类——一个带有颜色的字符串。如果您似乎很清楚将彩色逗号传递给join
不是错误并且应该导致"1,2"
(即使该字符串不会被着色),那么请to_str
在 ColoredString 上实现。
Zverok有一篇很好理解的文章,关于何时使用什么(用 to_h 和 to_hash 解释)。
实现这些方法的对象是否可以转换为字符串 -> 使用to_s
或者它是某种(增强的)字符串的类型 -> 使用to_str
我在 gem 'configuration'(GitHub和Configuration.rb)中看到了to_hash
Configuration 类在实践中的有意义的用法
它代表——顾名思义——提供的配置,实际上是一种散列(具有附加功能),而不是可转换为散列。