Сведения о вопросе

Sadijon

21:06, 1st October, 2020

Теги

ruby   string   io   buffer    

Почему у Ruby нет настоящего StringBuffer или StringIO?

Просмотров: 427   Ответов: 5

Недавно я прочитал хороший пост об использовании StringIO в Ruby. Однако автор не упоминает, что StringIO -это просто "I.", нет "O.", вы не можете этого сделать, например:

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

Ruby действительно нуждается в StringBuffer точно так же, как и тот, который есть у Java. StringBuffers служат двум важным целям. Во-первых, они позволяют вам проверить выходную половину того, что делает Ruby StringIO. Во-вторых, они полезны для создания длинных струн из маленьких частей-то, что Джоэл напоминает нам снова и снова, в противном случае очень медленно.

Есть ли хорошая замена?

Это правда, что строки в Ruby изменчивы, но это не значит, что мы всегда должны полагаться на эту функциональность. Если stuff является большим, то требования к производительности и памяти этого, например, действительно плохи.

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

"correct" способ сделать это в Java-это:

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

Хотя мой Java немного заржавел.



  Сведения об ответе

SSESION

01:36, 11th August, 2020

Я просмотрел документацию ruby для StringIO , и похоже, что вы хотите StringIO#string , а не StringIO#to_s

Таким образом, измените свой код на:

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


  Сведения об ответе

PIRLO

21:06, 1st October, 2020

Как и другие объекты типа IO в Ruby, при записи в IO указатель символов перемещается вперед.

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


  Сведения об ответе

pumpa

21:06, 1st October, 2020

Я сделал несколько тестов, и самый быстрый подход-это использование метода 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 просто использует String#<< в Ruby.


  Сведения об ответе

SEEYOU

14:41, 14th August, 2020

Ваш пример работает в 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 - это просто выводит идентификатор объекта.


  Сведения об ответе

PIRLO

10:02, 24th August, 2020

Ну, а StringBuffer не совсем так необходим в Ruby, главным образом потому, что строки в Ruby изменчивы... таким образом, вы можете построить строку, изменив существующую строку, а не создавать новые строки с каждым конкатом.

В качестве примечания вы также можете использовать специальный синтаксис строки, где вы можете построить строку, которая ссылается на другие переменные внутри строки,что делает ее очень читаемой. Считать:

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

Эти строки также могут содержать выражения, а не только переменные... такие как:

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться