可能的重复项:
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"]"
并不是真的在寻找一种不同的方法来做到这一点,只是对两个版本之间的变化感到好奇。
以下是 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
在版本之间来回切换。
to_s
已更改为实际执行将对象转换为字符串应执行的操作。
考虑 1.8 实现...
- 当您将方法发送到数组对象
to_s
时,它实际上会array_object.join('').to_s
。恕我直言,这做得太多了。 - 此实现还错误地表示数组对象。
to_s
方法主要与inspect
方法齐头并进(如果我错了,请_correct我,因为我在这里工作)。如果你在这里查看to_s
方法的输出,你无法判断对象是Array
、String
还是Fixnum
类。
进入 1.9 实施...
- 输出的结构清楚地表明对象是一个数组。
话虽如此,我认为这是 Ruby 团队的 UX 设计决策......因为 1.8 中的to_s
要快得多!
考虑一下这个微基准...
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 |
这就是我到目前为止所拥有的一切。随时欢迎评论(:
看起来Ruby对.to_s
做的事情变得更加聪明。 它曾经是愚蠢的,并且由于某种原因并排列出数组中的所有条目。 在 ruby 1.9 中,它获取数组并将其转换为字符串。 这是一种更聪明的处理.to_s
的方法。