سؤال

أنا أستخدم هذا الرمز للسماح للمستخدم بإدخال الأسماء بينما يقوم البرنامج بتخزينها في مصفوفة حتى يدخل سلسلة فارغة (يجب عليه الضغط على زر الإدخال بعد كل اسم):

people = []
info = 'a' # must fill variable with something, otherwise loop won't execute

while not info.empty?
    info = gets.chomp
    people += [Person.new(info)] if not info.empty?
end

سيبدو هذا الرمز أجمل بكثير في حالة ...حائط اللوب:

people = []

do
    info = gets.chomp
    people += [Person.new(info)] if not info.empty?
while not info.empty?

في هذا الكود ليس من الضروري تعيين معلومات لبعض السلاسل العشوائية.

لسوء الحظ، لا يبدو أن هذا النوع من الحلقات موجود في روبي.هل يمكن لأي شخص أن يقترح طريقة أفضل للقيام بذلك؟

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

المحلول

حذر:

ال begin <code> end while <condition> تم رفضه من قبل مؤلف روبي ماتز.بدلا من ذلك يقترح استخدام Kernel#loop, ، على سبيل المثال.

loop do 
  # some code here
  break if <condition>
end 

هنا تبادل البريد الإلكتروني في 23 نوفمبر 2005 حيث صرح ماتز:

|> Don't use it please.  I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised.  What do you regret about it?

Because it's hard for users to tell

  begin <code> end while <cond>

works differently from

  <code> while <cond>

روزيتا كود ويكي لديه قصة مماثلة:

خلال نوفمبر 2005، أعرب يوكيهيرو ماتسوموتو، مبتكر روبي، عن أسفه لميزة الحلقة هذه واقترح استخدام Kernel#loop.

نصائح أخرى

لقد وجدت المقتطف التالي أثناء قراءة المصدر لـ Tempfile#initialize في مكتبة روبي الأساسية:

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)

للوهلة الأولى، افترضت أنه سيتم تقييم معدّل while قبل محتويات البداية...النهاية، لكن هذا ليس هو الحال.يراقب:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

كما هو متوقع، سيستمر تنفيذ الحلقة عندما يكون المُعدِّل صحيحًا.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

على الرغم من أنني سأكون سعيدًا بعدم رؤية هذا المصطلح مرة أخرى، إلا أن البداية...النهاية قوية جدًا.فيما يلي لغة شائعة لحفظ طريقة ذات سطر واحد بدون معلمات:

def expensive
  @expensive ||= 2 + 2
end

إليك طريقة قبيحة ولكنها سريعة لحفظ شيء أكثر تعقيدًا:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

كتبها في الأصل جيريمي فورهيس.تم نسخ المحتوى هنا لأنه يبدو أنه قد تمت إزالته من الموقع الأصلي.يمكن العثور على نسخ أيضًا في أرشيف الويب وفي منتدى روبي باز.-بيل السحلية

مثله:

people = []

begin
  info = gets.chomp
  people += [Person.new(info)] if not info.empty?
end while not info.empty?

مرجع: يقوم Ruby's Hidden بعمل {} while () Loop

وماذا عن هذا؟

people = []

until (info = gets.chomp).empty?
  people += [Person.new(info)]
end

إليك النص الكامل للمقالة من رابط hubbardr الميت إلى مدونتي.

لقد وجدت المقتطف التالي أثناء قراءة المصدر لـ Tempfile#initialize في مكتبة روبي الأساسية:

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)

للوهلة الأولى، افترضت while سيتم تقييم المعدل قبل محتويات begin...end, ، لكن هذه ليست هي القضية.يراقب:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

كما هو متوقع، سيستمر تنفيذ الحلقة عندما يكون المُعدِّل صحيحًا.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

بينما سأكون سعيدًا بعدم رؤية هذا المصطلح مرة أخرى، begin...end قوية جدًا.فيما يلي لغة شائعة لحفظ طريقة ذات سطر واحد بدون معلمات:

def expensive
  @expensive ||= 2 + 2
end

إليك طريقة قبيحة ولكنها سريعة لحفظ شيء أكثر تعقيدًا:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

هذا يعمل بشكل صحيح الآن:

begin
    # statment
end until <condition>

ولكن من الممكن أن تتم إزالته في المستقبل، لأن begin البيان غير بديهي.يرى: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745

أوصى ماتز بالقيام بذلك بهذه الطريقة:

loop do
    # ...
    break if <condition>
end

من ما جمعته، ماتز لا يحب البناء

begin
    <multiple_lines_of_code>
end while <cond>

لأن دلالاتها تختلف عن

<single_line_of_code> while <cond>

في ذلك ، يقوم البناء الأول بتنفيذ الكود أولاً قبل التحقق من الشرط ، ويختبر البناء الثاني الشرط أولاً قبل تنفيذ الكود (إن وجدت).أعتبر أن ماتز يفضل الاحتفاظ بالبنية الثانية لأنها تطابق بنية سطر واحد من عبارات if.

لم يعجبني أبدًا البناء الثاني حتى لو كانت العبارات.في جميع الحالات الأخرى ، يقوم الكمبيوتر بتنفيذ الكود من اليسار إلى اليمين (على سبيل المثال.|| و &&) من أعلى إلى أسفل.يقرأ البشر الكود من اليسار إلى اليمين من أعلى إلى أسفل.

أقترح التركيبات التالية بدلاً من ذلك:

if <cond> then <one_line_code>      # matches case-when-then statement

while <cond> then <one_line_code>

<one_line_code> while <cond>

begin <multiple_line_code> end while <cond> # or something similar but left-to-right

لا أعرف ما إذا كانت هذه الاقتراحات سيتم تحليلها مع بقية اللغة.ولكن على أي حال ، أحافظ على تنفيذ من اليسار إلى اليمين وكذلك تناسق اللغة.

a = 1
while true
  puts a
  a += 1
  break if a > 10
end

تفضل واحد اخر:

people = []
1.times do
  info = gets.chomp
  unless info.empty? 
    people += [Person.new(info)]
    redo
  end
end
ppl = []
while (input=gets.chomp)
 if !input.empty?
  ppl << input
 else
 p ppl; puts "Goodbye"; break
 end
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top