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

为什么';Ruby没有真正的StringBuffer或StringIO吗?,ruby,string,io,buffer,Ruby,String,Io,Buffer,我最近读了一篇关于在Ruby中使用StringIO的文章。但是,作者没有提到的是,StringIO只是一个“I”。没有“O”。你不能这样做,例如: s = StringIO.new s << 'foo' s << 'bar' s.to_s # => should be "foo\nbar" # => really is ''` 在Java中执行此操作的“正确”方法是: result = StringBuffer.new("") for(String s :

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

s = StringIO.new
s << 'foo'
s << 'bar'
s.to_s
# => should be "foo\nbar"
# => really is ''`
在Java中执行此操作的“正确”方法是:

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

虽然我的Java有点生疏。

好吧,在Ruby中StringBuffer并不是那么必要,主要是因为Ruby中的字符串是可变的。。。因此,您可以通过修改现有字符串而不是使用每个concat构造新字符串来构建字符串

需要注意的是,您还可以使用特殊的字符串语法,在这里您可以构建一个引用字符串中其他变量的字符串,这有助于非常可读的字符串构造。考虑:

first = "Mike"
last = "Stone"
name = "#{first} #{last}"
这些字符串还可以包含表达式,而不仅仅是变量。。。例如:

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

我查看了
StringIO
的ruby文档,它看起来像是您想要的,而不是
StringIO

因此,将代码更改为:

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

s您的示例在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"
irb(main):001:0>需要“stringio”
=>正确
irb(主):002:0>s=StringIO.new
=> #
irb(主):003:0>s#
irb(主要):004:0>s#
irb(主):005:0>s.string
=>“foobar”

除非我遗漏了您使用to_s的原因,它只输出对象id。

与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"
>s=StringIO.new
=> #
>>#
>>#
>>s.pos
=> 6
>>倒带
=> 0
>>美国雷德
=>“foobar”

我做了一些基准测试,最快的方法是使用
字符串#“Mega Maid?”从未听说过她。我也从未真正相信StringBuffers,但我总是使用它们,因为我害怕有人看到我的代码。但真的,这些东西有什么意义吗?可能是一个“太空球”的引用。Mega maid已经被删除,作为摆脱亵渎的附带伤害。你的字符串连接示例与Java代码并不等价。正如你所提到的,Ruby字符串是可变的,所以在Ruby中你只需要做:
stuff.Injection(“”){res,s | res我真的不明白为什么StringIO没有to|s方法。它是一个管理字符串的类,所以如果你想要那个字符串,你必须特别要求它。它应该有to|s方法,因为这是Ruby约定,但它没有。(如果我错了,有人可以纠正我)这当然是真的,而且它对于短插值非常有用。但是,它对于构建长字符串(如HTML页面)来说很糟糕。请看,当然,但是对于构建HTML页面,为什么不使用为该函数构建的东西,如HAML或ERB?re:“Schlemiel the Painter's algorithm”如果您像上面那样使用StringIO,Joel Spolsky的批评不适用。StringIO有一个查找指针,就像文件一样。不需要每次都重新计算字符串的结尾。对于更长的字符串,您可以使用%{}或者像厄尔建议的那样的库。我真的不需要这个,因为有
StringIO#read
,但我总是喜欢知道不止一种方法来做某事。嗯,我的意思是
StringIO#string
这个基准测试使用了什么版本的ruby?哇。这应该是正确的答案,因为string是最快的。测试ruby 2.1.5上的d和相同的结果。当ruby使字符串不可变时会发生什么?这样的微优化最终是一个地狱。如果你想在很长的字符串中添加一些字符,会发生什么?我认为
StringIO
会更快。字符串连接解决方案不会处理冻结的字符串文本,但是
StringIO
作品
>> s = StringIO.new
=> #<StringIO:0x3659d4>
>> s << 'foo'
=> #<StringIO:0x3659d4>
>> s << 'bar'
=> #<StringIO:0x3659d4>
>> s.pos
=> 6
>> s.rewind
=> 0
>> s.read
=> "foobar"
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)
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)