【问题标题】:to_s vs. to_str (and to_i/to_a/to_h vs. to_int/to_ary/to_hash) in RubyRuby 中的 to_s 与 to_str(以及 to_i/to_a/to_h 与 to_int/to_ary/to_hash)
【发布时间】:2012-06-26 06:41:13
【问题描述】:

我正在学习 Ruby,我看到了一些让我有点困惑的方法,特别是 to_sto_str(同样,to_i/to_intto_a/@987654326 @, & to_h/to_hash)。我读到的内容解释了较短的形式(例如to_s)用于显式转换,而较长的形式用于隐式转换。

我真的不明白to_str 将如何实际使用。字符串以外的东西会定义to_str吗?你能给出这个方法的实际应用吗?

【问题讨论】:

    标签: ruby string methods


    【解决方案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_ito_s] 并不是特别严格:例如,如果一个对象具有某种体面的字符串表示形式,它可能会有一个 to_s 方法... [to_int 和 @987654340 @] 是严格的转换函数:只有当 [your] 对象可以自然地在每个可以使用字符串或整数的地方使用时,您才能实现它们。

    Older Ruby documentation from the Pickaxe 有话要说:

    与几乎所有类都支持的to_s 不同,to_str 通常只由那些行为类似于字符串的类实现。

    例如,除了IntegerFloatNumeric 都实现了to_intto_i 等效于to_str),因为它们都可以很容易地替换一个整数(它们是所有实际数字)。除非你的类与 String 有同样紧密的关系,否则你不应该实现 to_str

    【讨论】:

    • 安德鲁,谢谢。但在实际意义上,“那些行为像字符串的类”是什么意思?这是否意味着它们实现了与字符串相同的方法?如果对象已经像字符串一样,to_str 除了 self 还会返回什么?
    • @JeffStorey 是的。除非你的类可以被字符串替换,否则你不应该实现to_str。 String 对to_sto_str 的实现就是这样做的:返回它们自己。实现to_str 是一种验证您的行为是否像字符串一样的方法。许多核心方法以这种方式使用to_str。我引用的博文值得一读:)
    • 安德鲁,谢谢。我确实看过那篇文章,但我仍然有点不清楚。有没有可能实现 to_str 的时候?那是我真正感到困惑的部分......我想不出一个实际的例子。
    • @JeffStorey 除非您正在创建一个类似于 String 的类并且至少实现它所做的所有方法,否则不会。当然,在这种情况下,无论如何您都可能拥有 String 子类,并且可以免费获得它。何时这样做的一个很好的例子是 Ruby 的数字:Float、Integer 和 Numeric 都实现了to_intto_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'GitHubConfiguration.rb)中的 Configuration 类的实践中看到了 to_hash 的有意义用法

      它代表——顾名思义——提供的配置,实际上是一种哈希(具有附加功能),而不是可以转换为一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多