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

时间:2008-09-25 23:15:04

标签: ruby loops

我正在使用此代码让用户输入名称,同时程序将它们存储在一个数组中,直到它们输入一个空字符串(它们必须在每个名称后按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循环中看起来更好:

people = []

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

在此代码中,我不必将信息分配给某个随机字符串。

不幸的是,Ruby中似乎不存在这种类型的循环。任何人都可以建议一个更好的方法吗?

10 个答案:

答案 0 :(得分:615)

<强>注意

Ruby的作者Matz拒绝了begin <code> end while <condition>。相反,他建议使用Kernel#loop,例如

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

2005年11月23日这里是an email exchange,Matz说:

|> Don't use it please.  I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised.  What do you regret about it?

Because it's hard for users to tell

  begin <code> end while <cond>

works differently from

  <code> while <cond>

RosettaCode wiki也有类似的故事:

  

2005年11月,Ruby的创建者Yukihiro Matsumoto对这个循环功能表示遗憾并建议使用Kernel#loop。

答案 1 :(得分:186)

  

我在Ruby核心库中读取Tempfile#initialize的源代码时发现了以下代码段:

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
     

虽然我很高兴再也看不到这个成语,但开始......结束是非常强大的。以下是一个常见的成语,用于记忆没有参数的单线方法:

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

最初由Jeremy Voorhis撰写。内容已在此处复制,因为它似乎已从原始网站中删除。也可以在Web ArchiveRuby Buzz Forum找到副本。 - 蜥蜴

答案 2 :(得分:100)

像这样:

people = []

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

参考:Ruby's Hidden do {} while () Loop

答案 3 :(得分:43)

这个怎么样?

people = []

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

答案 4 :(得分:11)

以下是hubbardr与博客的死链接的全文文章。

我在Ruby核心库中读取Tempfile#initialize的源代码时发现了以下代码段:

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非常强大。以下是一个常见的成语,用于记忆没有参数的单线方法:

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

答案 5 :(得分:8)

现在可以正常使用:

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

答案 6 :(得分:5)

从我收集的内容来看,Matz不喜欢构造

begin
    <multiple_lines_of_code>
end while <cond>

因为,它的语义与

不同
<single_line_of_code> while <cond>

因为第一个构造在检查条件之前首先执行代码, 第二个构造在执行代码之前首先测试条件(如果有的话)。我认为Matz更喜欢保留第二个结构,因为它匹配if语句的一个行结构。

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

我建议使用以下结构:

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

我不知道这些建议是否会用其他语言进行解析。但无论如何 我倾向于保持从左到右的执行以及语言的一致性。

答案 7 :(得分:3)

a = 1
while true
  puts a
  a += 1
  break if a > 10
end

答案 8 :(得分:2)

这是另一个:

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

答案 9 :(得分:-3)

ppl = []
while (input=gets.chomp)
 if !input.empty?
  ppl << input
 else
 p ppl; puts "Goodbye"; break
 end
end