为什么Ruby没有真正的StringBuffer或StringIO?

Jam*_*sen 52 ruby string io buffer

我最近阅读了一篇关于在Ruby中使用的好文章StringIO.但是,作者没有提到的是,这StringIO只是一个"我".没有"O".你不能这样做,例如:

s = StringIO.new
s << 'foo'
s << 'bar'
s.to_s
# => should be "foo\nbar"
# => really is ''`
Run Code Online (Sandbox Code Playgroud)

Ruby确实需要一个像Java一样的StringBuffer.StringBuffers有两个重要目的.首先,它们让您测试Ruby的StringIO所做的输出的一半.其次,它们对于从小部件构建长弦很有用 - Joel一次又一次地提醒我们的是非常慢的东西.

有替代品吗?

Ruby中的字符串确实是可变的,但这并不意味着我们应该始终依赖于该功能.如果stuff很大,例如,它的性能和内存要求非常糟糕.

result = stuff.map(&:to_s).join(' ')
Run Code Online (Sandbox Code Playgroud)

在Java中执行此操作的"正确"方法是:

result = StringBuffer.new("")
for(String s : stuff) {
  result.append(s);
}
Run Code Online (Sandbox Code Playgroud)

虽然我的Java有点生疏.

Mik*_*one 114

我查看了ruby文档StringIO,它看起来像你想要的是StringIO#string,而不是StringIO#to_s

因此,将您的代码更改为:

s = StringIO.new
s << 'foo'
s << 'bar'
s.string
Run Code Online (Sandbox Code Playgroud)


Col*_*tin 34

与Ruby中的其他IO类型对象一样,当您写入IO时,字符指针会前进.

>> s = StringIO.new
=> #<StringIO:0x3659d4>
>> s << 'foo'
=> #<StringIO:0x3659d4>
>> s << 'bar'
=> #<StringIO:0x3659d4>
>> s.pos
=> 6
>> s.rewind
=> 0
>> s.read
=> "foobar"
Run Code Online (Sandbox Code Playgroud)

皮肤这种猫的另一种方法.


jma*_*bia 24

我做了一些基准测试,最快的方法是使用该String#<<方法.使用StringIO有点慢.

s = ""; Benchmark.measure{5000000.times{s << "some string"}}
=>   3.620000   0.100000   3.720000 (  3.970463)

>> s = StringIO.new; Benchmark.measure{5000000.times{s << "some string"}}
=>   4.730000   0.120000   4.850000 (  5.329215)
Run Code Online (Sandbox Code Playgroud)

使用该String#+方法连接字符串是最慢的方法,有很多个数量级:

s = ""; Benchmark.measure{10000.times{s = s + "some string"}}
=>   0.700000   0.560000   1.260000 (  1.420272)

s = ""; Benchmark.measure{10000.times{s << "some string"}}
=>   0.000000   0.000000   0.000000 (  0.005639)
Run Code Online (Sandbox Code Playgroud)

所以我认为正确的答案是Java的等价物StringBuffer只是String#<<在Ruby中使用.


pal*_*sey 12

您的示例适用于Ruby - 我只是尝试过它.

irb(main):001:0> require 'stringio'
=> true
irb(main):002:0> s = StringIO.new
=> #<StringIO:0x2ced9a0>
irb(main):003:0> s << 'foo'
=> #<StringIO:0x2ced9a0>
irb(main):004:0> s << 'bar'
=> #<StringIO:0x2ced9a0>
irb(main):005:0> s.string
=> "foobar"
Run Code Online (Sandbox Code Playgroud)

除非我错过你使用to_s的原因 - 它只输出对象id.