Por que Ruby não tem um StringBuffer real ou StringIO?

votos
45

Recentemente li uma boa pós sobre o uso StringIOde Ruby. O que o autor não menciona, porém, é que StringIOé apenas um eu Não há nenhuma O. Você não pode fazer isso, por exemplo:

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

Rubi realmente precisa de um StringBuffer assim como o Java tem. StringBuffers têm duas finalidades importantes. Primeiro, eles permitem testar a metade do que StringIO de Ruby faz saída. Em segundo lugar, eles são úteis para a construção de cadeias longas de peças pequenas - algo que Joel lembra-nos uma e outra vez é outra forma muito, muito lento.

Existe um bom substituto?

É verdade que Cordas em Ruby são mutáveis, mas isso não significa que devemos sempre contar com essa funcionalidade. Se stufffor grande, as exigências do presente de desempenho e de memória, por exemplo, é muito ruim.

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

A maneira correta de fazer isso em Java é:

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

Embora meu Java é um pouco enferrujado.

Publicado 13/08/2008 em 19:19
fonte usuário
Em outras línguas...                            


5 respostas

votos
4

Bem, um StringBuffer não é tão necessária em Ruby, principalmente porque Cordas em Ruby são mutáveis ​​... assim você pode construir uma corda, modificando a cadeia existente em vez de construir novas cadeias com cada concat.

Como uma nota, você também pode usar uma sintaxe especial cadeia onde você pode construir uma corda que faz referência a outras variáveis ​​dentro da cadeia, o que contribui para a construção corda muito legível. Considerar:

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

Essas seqüências também podem conter expressões, não apenas variáveis ​​... tais como:

str = "The count will be: #{count + 1}"
count = count + 1
Respondeu 13/08/2008 em 19:31
fonte usuário

votos
105

Eu olhei para a documentação de rubi para StringIO, e parece que o que você quer é StringIO#string, nãoStringIO#to_s

Assim, alterar o código para:

s = StringIO.new
s << 'foo'
s << 'bar'
s.string
Respondeu 13/08/2008 em 19:41
fonte usuário

votos
11

Seu exemplo funciona em Ruby - Eu só tentei.

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"

A menos que eu estou perdendo a razão que você está usando to_s - que só gera o ID de objeto.

Respondeu 13/08/2008 em 19:46
fonte usuário

votos
29

Como outros objetos IO-tipo em Ruby, quando você escreve para um IO, os avanços ponteiro personagem.

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

Outra maneira de esfolar este gato.

Respondeu 09/08/2009 em 18:39
fonte usuário

votos
16

Eu fiz algumas referências e a abordagem mais rápida é usando o String#<<método. Usando StringIOé um pouco mais lento.

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)

Concatenar cadeias usando o String#+método é a abordagem mais lenta por várias ordens de magnitude:

>> 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)

Então eu acho que a resposta certa é que o equivalente a Java de StringBufferé simplesmente usando String#<<em Ruby.

Respondeu 07/11/2012 em 16:57
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more