Есть ли цикл "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 ... в то время как цикл:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
в этом коде мне не нужно присваивать информацию какой-то случайной строке.
к сожалению, этот тип цикла, кажется, не существует в Ruby. Кто-нибудь может предложить лучший способ сделать это?
10 ответов:
осторожностью:
The
begin <code> end while <condition>отвергается автором Руби 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 Форум. - Билл ящерица
такой:
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МАЦ рекомендовал делать это таким образом:
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
Comments