Ruby 中的 to_s 与 to_str(以及 to_i/to_a/to_h 与 to_int/to_ary/to_hash)
Posted
技术标签:
【中文标题】Ruby 中的 to_s 与 to_str(以及 to_i/to_a/to_h 与 to_int/to_ary/to_hash)【英文标题】:to_s vs. to_str (and to_i/to_a/to_h vs. to_int/to_ary/to_hash) in Ruby 【发布时间】:2012-06-26 06:41:13 【问题描述】:我正在学习 Ruby,我看到了一些让我有点困惑的方法,特别是 to_s
与 to_str
(同样,to_i
/to_int
、to_a
/@987654326 @, & to_h
/to_hash
)。我读到的内容解释了较短的形式(例如to_s
)用于显式转换,而较长的形式用于隐式转换。
我真的不明白to_str
的实际使用方式。字符串以外的东西会定义to_str
吗?你能给出这个方法的实际应用吗?
【问题讨论】:
【参考方案1】:首先请注意,所有这些都适用于每对“短”(例如to_s
/to_i
/to_a
/to_h
)与“长”(例如to_str
/to_int
/ to_ary
/to_hash
) Ruby 中的强制方法(针对它们各自的类型),因为它们都具有相同的语义。
它们有不同的含义。你不应该实现to_str
,除非你的对象行为像一个字符串,而不是仅仅可表示一个字符串。实现to_str
的唯一核心类是String 本身。
来自Programming Ruby(引自this blog post,值得一读):
[
to_i
和to_s
] 并不是特别严格:例如,如果一个对象具有某种体面的字符串表示形式,它可能会有一个to_s
方法... [to_int
和 @987654340 @] 是严格的转换函数:只有当 [your] 对象可以自然地在每个可以使用字符串或整数的地方使用时,您才能实现它们。
Older Ruby documentation from the Pickaxe 有话要说:
与几乎所有类都支持的
to_s
不同,to_str
通常只由那些行为类似于字符串的类实现。
例如,除了Integer,Float 和Numeric 都实现了to_int
(to_i
等效于to_str
),因为它们都可以很容易地替换一个整数(它们是所有实际数字)。除非你的类与 String 有同样紧密的关系,否则你不应该实现 to_str
。
【讨论】:
安德鲁,谢谢。但在实际意义上,“那些行为像字符串的类”是什么意思?这是否意味着它们实现了与字符串相同的方法?如果对象已经像字符串一样,to_str 除了 self 还会返回什么? @JeffStorey 是的。除非你的类可以被字符串替换,否则你不应该实现to_str
。 String 对to_s
和to_str
的实现就是这样做的:返回它们自己。实现to_str
是一种验证您的行为是否像字符串一样的方法。许多核心方法以这种方式使用to_str
。我引用的博文值得一读:)
。
安德鲁,谢谢。我确实看过那篇文章,但我仍然有点不清楚。有没有可能实现 to_str 的时候?那是我真正感到困惑的部分......我想不出一个实际的例子。
@JeffStorey 除非您正在创建一个类似于 String 的类并且至少实现它所做的所有方法,否则不会。当然,在这种情况下,无论如何您都可能拥有 String 子类,并且可以免费获得它。何时这样做的一个很好的例子是 Ruby 的数字:Float、Integer 和 Numeric 都实现了to_int
(to_i
的“to_str
”等效项),因为它们可以很容易地相互替换。
查看 Ruby koans about_to_str 示例以获得更多信息。【参考方案2】:
要了解是否应该使用/实现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"
(即使该字符串不会被着色),那么 do 实现 to_str
在彩色字符串上。
【讨论】:
【参考方案3】:Zverok 有一篇很好理解的文章,关于何时使用什么(用 to_h 和 to_hash 解释)。
你的实现这些方法的对象是否可以转换为字符串
-> 使用to_s
或者它是某种(增强的)字符串的类型
-> 使用to_str
我在 gem 'configuration'(GitHub 和 Configuration.rb)中的 Configuration 类的实践中看到了 to_hash
的有意义用法
它代表——顾名思义——提供的配置,实际上是一种哈希(具有附加功能),而不是可以转换为一个。
【讨论】:
以上是关于Ruby 中的 to_s 与 to_str(以及 to_i/to_a/to_h 与 to_int/to_ary/to_hash)的主要内容,如果未能解决你的问题,请参考以下文章
如何反转 Hash.inspect 或 Array.inspect? (又名 .to_s)在 Ruby 中