2008-09-25 2 views
392

Я использую этот код, чтобы позволить пользователю вводить в именах, пока программа сохраняет их в массиве, пока они не войдут в пустую строку (они должны нажать клавишу ВВОД после каждого имени):Есть ли цикл «do ... while» в Ruby?

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 

Этот код будет выглядеть гораздо лучше в то время ... while loop:

people = [] 

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

В этом коде мне не нужно присваивать информацию некоторой случайной строке.

К сожалению, этот тип цикла, похоже, не существует в Ruby. Может ли кто-нибудь предложить лучший способ сделать это?

+1

Я думаю, что обычный цикл while выглядит лучше, и его легче читать. – Magne 2013-11-14 10:57:50

+1

@Jeremy Ruten есть ли шанс, что вы были бы заинтересованы в изменении принятого ответа на ответ Siwei Shen: `loop do; ...; перерыв, если ...; end`? – 2014-05-03 22:08:55

ответ

525

ВНИМАНИЕ:

begin <code> end while <condition> отклонен автором Ruby Matz. Вместо этого он предлагает использовать Kernel#loop, например.

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

Для более подробной информации, пожалуйста, обращайтесь: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 (or via Wayback), и эта вики: http://rosettacode.org/wiki/Loops/Do-while#Ruby

184

Первоначально написанный Jeremy Voorhis. Содержимое было скопировано здесь, потому что оно, кажется, было снято с исходного сайта. Копии также можно найти в Web Archive и по адресу Ruby Buzz Forum. -Билль Ящерица

я нашел следующий фрагмент при чтении источника для Tempfile#initialize в базовой библиотеке Ruby:

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) 

На первый взгляд, я предположил, модификатор в то время как будет оцениваться, прежде чем содержание от начала ... конец, но это не так. Обратите внимание:

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

Хотя я был бы счастлив никогда больше не видеть эту идиому, начните ... конец довольно мощный. Ниже общая идиома memoize метод один-лайнер с не Params:

def expensive 
    @expensive ||= 2 + 2 
end 

Вот уродливый, но быстрый способ memoize нечто более сложное:

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 
+5

Предоставлено машиной Wayback: http://web.archive.org/web/20080206125158/http://archive.jvoorhis.com/articles/2007/06/13/ruby-hidden-do-while-loop – bta 2010-07-22 15:32:49

+52

Это поэтому, когда вы связываетесь с внешним сайтом, я всегда буду копировать соответствующую информацию в свой ответ здесь. – davr 2010-09-09 00:03:34

+9

Почему вы ожидаете, что модификатор while будет оценен до того, как будет начато содержимое ... end? Вот так и должно быть. Петли должны работать. И почему вы «счастливы никогда больше не увидеть эту идиому?» Что с этим не так? Я смущен. – bergie3000 2013-02-13 19:33:03

40

Как насчет этого?

people = [] 

until (info = gets.chomp).empty? 
    people += [Person.new(info)] 
end 
-3
ppl = [] 
while (input=gets.chomp) 
if !input.empty? 
    ppl << input 
else 
p ppl; puts "Goodbye"; break 
end 
end 
11

Вот полный текст статьи из hubbardr в мертвой ссылке на мой блог.

я нашел следующий фрагмент при чтении источника для Tempfile#initialize в базовой библиотеке Ruby:

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 является достаточно мощным. Ниже общая идиома memoize метод один-лайнер с не Params:

def expensive 
    @expensive ||= 2 + 2 
end 

Вот уродливый, но быстрый способ memoize нечто более сложное:

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 
3
a = 1 
while true 
    puts a 
    a += 1 
    break if a > 10 
end 
1

Вот еще один один:

people = [] 
1.times do 
    info = gets.chomp 
    unless info.empty? 
    people += [Person.new(info)] 
    redo 
    end 
end 
8

Это правильно работает в настоящее время:

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 
5

Из того, что я понимаю, Мац не нравится конструкта

begin 
    <multiple_lines_of_code> 
end while <cond> 

потому, что это семантика отличается

<single_line_of_code> while <cond> 

в том, что первая конструкция выполняет код сначала перед проверкой c ondition, , а вторая конструктор проверяет условие прежде, чем он выполнит код (если когда-либо). Я полагаю, что Matz предпочитает сохранить вторую конструкцию, потому что она соответствует одной строковой конструкции операторов if.

Мне никогда не нравилась вторая конструкция даже для операторов 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 

Я не знаю, если эти предложения будут разбирать с остальной частью языка. Но в любом случае Я предпочитаю сохранить выполнение слева направо, а также согласованность языка.