3

可能重复:
Ruby 1.9 Array.to_s 的行为不同?

我想知道是否有人能告诉我 Ruby 1.8.7 和 Ruby 1.9.3 之间发生了什么变化。我在下面列出了一个示例,它在 2 个版本中的行为完全不同,但根据 Ruby 文档,这些版本之间似乎没有任何变化。

红宝石 1.8

number = '123-45-6789' 
# => "123-45-6789"
number.scan(/[0-9]/)
# => ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
number.scan(/[0-9]/).to_s
# => "123456789"

红宝石 1.9

number = '123-45-6789'
# => "123-45-6789" 
number.scan(/[0-9]/)
# => ["1", "2", "3", "4", "5", "6", "7", "8", "9"]    
number.scan(/[0-9]/).to_s
# => "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"]"

并不是真的在寻找一种不同的方法来做到这一点,只是好奇两个版本之间发生了什么变化。

4

3 回答 3

5

以下是 Ruby 源代码中的实际内容:

1.8.7:

rb_ary_to_s(ary)
    VALUE ary;
{
    if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
    return rb_ary_join(ary, rb_output_fs);
}

换句话说,在 1.8.7 中,to_s调用join.

1.9.3:

rb_ary_inspect(VALUE ary)
{
    if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
    return rb_exec_recursive(inspect_ary, ary, 0);
}

VALUE
rb_ary_to_s(VALUE ary)
{
    return rb_ary_inspect(ary);
}

换句话说,在 1.9.3 中,to_s委托给inspect.

注意:将来,如果您想知道在两个版本之间观察到的差异,您可以尝试查看源代码。很容易从这里拉下来:https ://github.com/ruby/ruby

当然,并不是所有的东西都在那里很容易找到,但是如果你四处搜索一下,你通常可以找到好的线索。在这种情况下,array.c有你正在寻找的东西。

git checkout ruby_1_8_7然后您可以通过发出和在版本之间来回切换git checkout ruby_1_9_3

于 2012-10-01T19:09:08.227 回答
2

to_s更改为实际执行将对象转换为字符串应该执行的操作。

考虑 1.8 的实现...

  1. 当您将 toto_s方法发送到数组对象时,它实际上是array_object.join('').to_s. 这个恕我直言做得太多了。
  2. 此实现也歪曲了数组对象。该to_s方法主要与该inspect方法密切相关(如果我错了,请纠正我,因为我在这里工作不正常)。如果您应该在to_s这里查看方法的输出,您将无法判断该对象是否属于Array,StringFixnum类。

进入 1.9 实现...

  1. 输出的结构清楚地表明对象是一个数组。

话虽如此,我认为这是 Ruby 团队的 UX 设计决定……因为to_s1.8 版本的速度要快得多!

考虑这个微基准...

OS_X_Terminal $> time ruby -e "(1..1000000).to_a.map(&:to_s).to_s"

| Ruby Version | average runtime |
|    1.9.3     |      1.678      |
|    1.9.2     |      1.817      |
|    1.8.7     |      1.106      |

这就是我到目前为止所拥有的。随时欢迎评论(:

于 2012-10-01T18:49:33.233 回答
0

看起来 ruby​​ 在做什么方面变得更聪明了.to_s。它曾经很愚蠢,出于某种原因并排列出了数组中的所有条目。在 ruby​​ 1.9 中,它接受数组并将其转换为字符串。那是一种更聪明的处理方式.to_s

于 2012-10-01T18:18:17.287 回答