Есть ли в Ruby цикл "do ... while"?
Я использую этот код, чтобы позволить пользователю вводить имена, в то время как программа сохраняет их в массиве, пока они не введут пустую строку (они должны нажимать ввод после каждого имени):
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
Этот код будет выглядеть намного лучше в цикле do... while:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
В этом коде мне не нужно присваивать информацию какой-либо случайной строке.
К сожалению, этот тип цикла не существует в Ruby. Кто-нибудь может предложить лучший способ сделать это?
10 ответов
ВНИМАНИЕ:
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 ( или через Wayback) и эту вики: http: // rosettacode. орг / вики / Loops / Do-то время # рубин
Я нашел следующий фрагмент при чтении источника для
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
Как и следовало ожидать, цикл продолжит выполняться, пока модификатор имеет значение true.
>> 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
Первоначально написано Джереми Вурхис. Содержание было скопировано здесь, потому что, кажется, оно было удалено с исходного сайта. Копии также можно найти в веб-архиве и на форуме Ruby Buzz. -Билл Ящерица
Как это:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Как насчет этого?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
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
Вот полный текст статьи из мертвой ссылки Хаббардра на мой блог.
Я нашел следующий фрагмент при чтении источника для 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
Как и следовало ожидать, цикл продолжит выполняться, пока модификатор имеет значение true.
>> 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
<multiple_lines_of_code>
end while <cond>
потому что это семантика отличается от
<single_line_of_code> while <cond>
тем, что первая конструкция выполняет код сначала перед проверкой условия, а вторая конструкция сначала проверяет условие перед тем, как выполнить код (если когда-либо). Я полагаю, что Матц предпочитает сохранять вторую конструкцию, потому что она соответствует одной строковой конструкции оператора 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
Я не знаю, будут ли эти предложения разбираться с остальным языком. Но в любом случае я предпочитаю сохранять исполнение слева направо, а также согласованность языков.
Вот еще один:
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