2008-08-13 70 views
43

我最近读了一个很好的post在Ruby中使用StringIO。然而作者没有提到的是StringIO只是一个“I”。没有“O”。您无法做到这一点,例如:为什么Ruby没有真正的StringBuffer或StringIO?

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

红宝石确实需要一个StringBuffer就像一个Java有。 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

“Mega Maid?”从来没有听说过她。从来没有真正相信StringBuffers,但我总是用它们来担心有人看到我的代码。但是,真的,这些东西总合起来了吗? – 2009-05-06 01:53:03

+3

可能是'SpaceBalls'的参考。 – 2010-08-30 16:59:35

+2

巨型女佣已被删除作为摆脱亵渎的附带损害。 – 2011-05-09 03:52:29

回答

102

我看着红宝石文档StringIO,它看起来像你想要的是StringIO#string ,不StringIO#to_s

因此,你的代码更改为:

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

嘛,一个StringBuffer是不是很在Ruby中必要的,这主要是因为字符串在Ruby中是可变的,所以......你可以通过修改现有的字符串,而不是每个CONCAT构建新的字符串建立一个字符串。

作为一个说明,你还可以使用特殊字符串语法,你可以建立它引用的字符串,这使得非常可读的字符串建筑内的其他变量的字符串。试想一下:

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

这些字符串也可以包含表达式,而不只是变量...如:

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

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

29

与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" 

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

16

我做了一些基准,并以最快的方式是使用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#<<

相关问题