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

我最近读了一篇关于在Ruby中使用StringIO的好post 。 然而作者没有提到的是, StringIO只是一个“我”。 没有“O” 你不能这样做,例如:

 s = StringIO.new s << 'foo' s << 'bar' s.to_s # => should be "foo\nbar" # => really is ''` 

Ruby确实需要一个StringBuffer,就像Java一样。 StringBuffers有两个重要的用途。 首先,他们让你testing一下Ruby的StringIO的输出结果。 其次,它们对于从小部件中构build长弦是有用的 – Joel一再提醒我们的事情是非常缓慢的。

有没有好的替代品?

Ruby中的string是可变的,但这并不意味着我们应该总是依赖于这个function。 如果stuff很大,那么这个性能和内存要求就非常糟糕。

 result = stuff.map(&:to_s).join(' ') 

在Java中这样做的“正确”方式是:

 result = StringBuffer.new("") for(String s : stuff) { result.append(s); } 

虽然我的Java有点生疏。

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

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

 s = StringIO.new s << 'foo' s << 'bar' s.string 

像Ruby中的其他IOtypes的对象一样,当你写入一个IO时,字符指针前进。

 >> s = StringIO.new => #<StringIO:0x3659d4> >> s << 'foo' => #<StringIO:0x3659d4> >> s << 'bar' => #<StringIO:0x3659d4> >> s.pos => 6 >> s.rewind => 0 >> s.read => "foobar" 

另一种方法来剥皮这只猫。

我做了一些基准,最快的方法是使用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) 

使用String#+方法连接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) 

所以我认为正确的答案是相当于Java的StringBuffer是在Ruby中简单地使用String#<<

你的例子在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" 

除非我错过了使用to_s的原因 – 只输出对象id。

那么,Ruby中的StringBuffer并不是非常必要,主要是因为Ruby中的string是可变的…因此,您可以通过修改现有string来构buildstring,而不是用每个concat构造新的string。

注意,你也可以使用特殊的string语法,在那里你可以build立一个string来引用string中的其他variables,这使得string的构造非常可读。 考虑:

 first = "Mike" last = "Stone" name = "#{first} #{last}" 

这些string也可以包含expression式,而不仅仅是variables,例如:

 str = "The count will be: #{count + 1}" count = count + 1