Есть ли цикл "do ... while" в Ruby?
Я использую этот код, чтобы позволить пользователю вводить имена, пока программа сохраняет их в массиве, пока они не введут пустую строку (они должны нажать enter после каждого имени):
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 loop:
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.org/wiki/Loops/Do-while#Ruby
Я нашел следующий фрагмент при чтении источника для
Tempfile#initialize
в библиотеке Ruby core: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...конец, но это не так. Заметьте:
>> 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
первоначально написал Джереми Voorhis. Содержимое было скопировано здесь, потому что оно, похоже, было снято с исходного сайта. Копии также можно найти в Веб-Архив и Ruby Buzz Форум. - Ящерица Билл!--26-->
такой:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
вот полный текст статьи из мертвой ссылки хаббардра на мой блог.
Я нашел следующий фрагмент при чтении источника для Tempfile#initialize
в библиотеке Ruby core:
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
# statment
end until <condition>
но, это может быть удалено в будущем, потому что begin
утверждение нелогично. Смотри:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz рекомендовал сделать это таким образом:
loop do
# ...
break if <condition>
end
из того, что я понял, мацу не нравится конструкция
begin
<multiple_lines_of_code>
end while <cond>
потому что, это семантика отличается, чем
<single_line_of_code> while <cond>
в том, что первая конструкция сначала выполняет код перед проверкой условия, и вторая конструкция сначала проверяет условие, прежде чем выполнять код (если вообще). Я полагаю, что Matz предпочитает сохранить вторую конструкцию, потому что она соответствует одной строчной конструкции операторов 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