سؤال

قرأت مؤخرا لطيفة بريد على استخدام StringIO في روبي.لكن ما لم يذكره المؤلف هو ذلك StringIO هو مجرد "I." لا يوجد "O." أنت لا أستطيع افعل هذا، على سبيل المثال:

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

تحتاج روبي حقًا إلى StringBuffer تمامًا مثل تلك الموجودة في Java.يخدم StringBuffers غرضين مهمين.أولاً، يسمحون لك باختبار نصف الناتج مما يفعله Ruby's StringIO.ثانيًا، إنها مفيدة في بناء أوتار طويلة من أجزاء صغيرة - وهو أمر يذكرنا به جويل مرارًا وتكرارًا وهو بخلاف ذلك بطيء جدًا.

هل هناك بديل جيد؟

صحيح أن السلاسل النصية في روبي قابلة للتغيير، لكن هذا لا يعني أننا يجب أن نعتمد دائمًا على هذه الوظيفة.لو stuff كبيرة، ومتطلبات الأداء والذاكرة، على سبيل المثال، سيئة حقًا.

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

الطريقة "الصحيحة" للقيام بذلك في Java هي:

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

على الرغم من أن Java الخاص بي صدئ بعض الشيء.

هل كانت مفيدة؟

المحلول

لقد نظرت إلى وثائق روبي ل StringIO, ، ويبدو أن ما تريده هو StringIO#string, ، لا StringIO#to_s

وبالتالي قم بتغيير الكود الخاص بك إلى:

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

نصائح أخرى

مثل الكائنات الأخرى من نوع IO في روبي، عندما تكتب إلى IO، يتقدم مؤشر الحرف.

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

لقد قمت ببعض المعايير وأسرع طريقة هي استخدام 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)

لذلك أعتقد أن الإجابة الصحيحة هي ما يعادل جافا StringBuffer يستخدم ببساطة String#<< في روبي.

مثالك يعمل في روبي - لقد جربته للتو.

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 - فهو يؤدي فقط إلى إخراج معرف الكائن.

حسنًا، StringBuffer ليس ضروريًا تمامًا في روبي، ويرجع ذلك أساسًا إلى أن السلاسل النصية في روبي قابلة للتغيير...وبالتالي يمكنك إنشاء سلسلة عن طريق تعديل السلسلة الموجودة بدلاً من إنشاء سلاسل جديدة مع كل سلسلة.

كملاحظة، يمكنك أيضًا استخدام صيغة سلسلة خاصة حيث يمكنك إنشاء سلسلة تشير إلى متغيرات أخرى داخل السلسلة، مما يجعل بناء السلسلة سهل القراءة للغاية.يعتبر:

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

يمكن أن تحتوي هذه السلاسل أيضًا على تعبيرات، وليس فقط متغيرات...مثل:

str = "The count will be: #{count + 1}"
count = count + 1
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top