Ruby中有“do … while”循环吗?

我使用这个代码让用户input名字,而程序将它们存储在一个数组中,直到他们input一个空string(他们必须在每个名字之后按回车键):

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? 

在这个代码中,我不必将信息分配给一些随机string。

不幸的是,这种types的循环似乎并不存在于Ruby中。 任何人都可以提出一个更好的方法来做到这一点?

小心

Ruby的作者Matz拒绝了begin <code> end while <condition> 。 相反,他build议使用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 )以及此wiki: http:// rosettacode。组织/维基/循环/不要同时#ruby

最初由Jeremy Voorhis撰写。 内容在这里被复制,因为它似乎已经从原始网站被删除。 副本也可以在Web Archive和Ruby Buzz Forum中find 。 – 蜥蜴

在读取Ruby核心库中的Tempfile#initialize的源代码时,我find以下代码片段:

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

虽然我很乐意再也看不到这个成语,但是开始…结束是相当强大的。 以下是一个常用的方法来记忆没有参数的单线程方法:

 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的隐藏do {} while()Loop

这个怎么样?

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

以下是来自hubbardr对我的博客的无效链接的全文。

在读取Ruby核心库中的Tempfile#initialize的源代码时,我find以下代码片段:

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

Matzbuild议这样做:

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

从我所收集的,马茨不喜欢这个构造

 begin <multiple_lines_of_code> end while <cond> 

因为,它的语义不同于

 <single_line_of_code> while <cond> 

因为第一个构造在检查条件之前首先执行代码,而第二个构造在执行代码之前首先testing条件(如果曾经的话)。 我认为Matz倾向于保留第二个构造,因为它匹配if语句的一行构造。

即使是if语句,我也不喜欢第二个构造。 在所有其他情况下,计算机从上到下执行代码从左到右(例如,||和&&)。 人类从左到右从上到下阅读代码。

我build议改为以下结构:

 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 

我不知道这些build议是否会与其他语言parsing。 但无论如何,我还是保持从左到右的执行以及语言的一致性。

 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