Question

J'ai récemment lu un joli poste sur l'utilisation StringIO en Rubis.Ce que l'auteur ne mentionne pas cependant, c'est que StringIO est juste un "I." Il n'y a pas de "O." Toi ne peut pas faites ceci, par exemple :

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

Ruby a vraiment besoin d'un StringBuffer, tout comme celui de Java.Les StringBuffers remplissent deux objectifs importants.Premièrement, ils vous permettent de tester la moitié de la sortie de ce que fait StringIO de Ruby.Deuxièmement, ils sont utiles pour construire de longues chaînes à partir de petites pièces – ce que Joel nous rappelle encore et encore est par ailleurs très très lent.

Existe-t-il un bon remplacement ?

Il est vrai que les chaînes dans Ruby sont mutables, mais cela ne signifie pas que nous devons toujours compter sur cette fonctionnalité.Si stuff est volumineux, les performances et les besoins en mémoire de celui-ci, par exemple, sont vraiment mauvais.

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

La façon "correcte" de procéder en Java est la suivante :

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

Bien que mon Java soit un peu rouillé.

Était-ce utile?

La solution

J'ai regardé la documentation Ruby pour StringIO, et il semble que ce que tu veux soit StringIO#string, pas StringIO#to_s

Changez donc votre code en :

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

Autres conseils

Comme les autres objets de type IO dans Ruby, lorsque vous écrivez dans une IO, le pointeur de caractère avance.

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

J'ai fait quelques benchmarks et l'approche la plus rapide consiste à utiliser le String#<< méthode.En utilisant StringIO est un peu plus lent.

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)

Concaténation de chaînes à l'aide de String#+ La méthode est l’approche la plus lente à plusieurs niveaux :

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)

Je pense donc que la bonne réponse est que l'équivalent de Java StringBuffer utilise simplement String#<< en Rubis.

Votre exemple fonctionne en Ruby - je viens de l'essayer.

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"

À moins que la raison pour laquelle vous utilisez to_s ne me manque, cela affiche simplement l'identifiant de l'objet.

Eh bien, un StringBuffer n'est pas aussi nécessaire dans Ruby, principalement parce que les chaînes dans Ruby sont mutables...ainsi, vous pouvez créer une chaîne en modifiant la chaîne existante au lieu de construire de nouvelles chaînes à chaque concat.

À noter que vous pouvez également utiliser une syntaxe de chaîne spéciale dans laquelle vous pouvez créer une chaîne qui fait référence à d'autres variables dans la chaîne, ce qui permet une construction de chaîne très lisible.Considérer:

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

Ces chaînes peuvent également contenir des expressions, pas seulement des variables...tel que:

str = "The count will be: #{count + 1}"
count = count + 1
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top