我最近在Ruby中使用StringIO
阅读了一篇很好的post。但是,作者没有提到的是StringIO
只是一个“我”。没有“O”。你不能这样做,例如:
s = StringIO.new
s << 'foo'
s << 'bar'
s.to_s
# => should be "foo\nbar"
# => really is ''`
Ruby确实需要一个像Java一样的StringBuffer。 StringBuffers有两个重要目的。首先,它们让您测试Ruby的StringIO所做的输出的一半。其次,它们对于从小部件构建长弦很有用 - Joel一次又一次地提醒我们的东西非常慢。
是否有一个好的替代品?
Ruby中的字符串确实是可变的,但这并不意味着我们应该始终依赖于该功能。如果stuff
很大,那么这个性能和内存要求非常糟糕。
result = stuff.map(&:to_s).join(' ')
在Java中执行此操作的“正确”方法是:
result = StringBuffer.new("")
for(String s : stuff) {
result.append(s);
}
虽然我的Java有点生疏。
答案 0 :(得分:114)
我查看了StringIO
的ruby文档,看起来你想要的是StringIO#string
,而不是StringIO#to_s
因此,请将您的代码更改为:
s = StringIO.new
s << 'foo'
s << 'bar'
s.string
答案 1 :(得分: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"
答案 2 :(得分:23)
我做了一些基准测试,最快的方法是使用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#+
方法连接字符串是最慢的方法,有很多个数量级:
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#<<
。
答案 3 :(得分: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"
除非我错过你使用to_s的原因 - 只输出对象id。
答案 4 :(得分:3)
嗯,在Ruby中,StringBuffer并不是必需的,主要是因为Ruby中的字符串是可变的...因此你可以通过修改现有的字符串来构建字符串,而不是用每个concat构造新的字符串。
作为一个注释,您还可以使用特殊的字符串语法,您可以在其中构建一个引用字符串中其他变量的字符串,这使得字符串构造非常易读。考虑:
first = "Mike"
last = "Stone"
name = "#{first} #{last}"
这些字符串也可以包含表达式,而不仅仅是变量......例如:
str = "The count will be: #{count + 1}"
count = count + 1