Ruby中有"do ... while"循环吗?

Jer*_*ten 448 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
Run Code Online (Sandbox Code Playgroud)

这个代码在do ... while循环中看起来更好看:

people = []

do
    info = gets.chomp
    people += [Person.new(info)] if not info.empty?
while not info.empty?
Run Code Online (Sandbox Code Playgroud)

在这段代码中,我不必将信息分配给一些随机字符串.

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

Siw*_*申思维 631

小心:

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

loop do 
  # some code here
  break if <condition>
end 
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745(或通过韦巴克),和这个wiki:HTTP:// rosettacode.组织/维基/循环/不要同时#红宝石

  • 发现.这种"开始结束时"方法似乎不对.谢谢你给我的饲料,我需要说服团队的其他成员. (17认同)
  • 所以,据我所知,start-end-while是"后悔"因为违反了修饰符的语义,即:在执行块之前检查它们,例如:puts k if!k.nil?.这里'if'是'修饰符':它被检查BEFORE,以确定是否执行'puts k'语句.这不是while/until循环的情况(当用作begin-end-block的修饰符时) !),在第一次执行后进行评估.也许这引起了后悔,但是我们有什么比旧的论坛帖子"更强大",有点像在其他许多场合使用的官方弃用? (4认同)
  • @James 根据链接的邮件,他说他“后悔”添加它。有时人们会犯错误,即使他们是语言设计者。 (3认同)
  • 看起来begin-end-while循环实际上是在运行循环之前评估条件.它与常规while循环之间的区别在于它保证至少运行一次.它只是足够接近......同时造成问题. (2认同)
  • 我花了很多时间来弄清楚为什么我使用这个红宝石'do-while'循环不起作用.你应该使用'除非'来更接近地模仿c风格的做法,否则你可能会像我一样忘记反转条件:p (2认同)

hub*_*rdr 188

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)
Run Code Online (Sandbox Code Playgroud)

乍一看,我假设while修饰符将在begin ... end的内容之前进行评估,但事实并非如此.注意:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil
Run Code Online (Sandbox Code Playgroud)

正如您所料,循环将在修饰符为true时继续执行.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil
Run Code Online (Sandbox Code Playgroud)

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

def expensive
  @expensive ||= 2 + 2
end
Run Code Online (Sandbox Code Playgroud)

这是一个丑陋但快速的方法来记忆更复杂的东西:

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
Run Code Online (Sandbox Code Playgroud)

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

  • 这就是为什么当链接到外部网站时,我总是确保将相关信息复制到我的答案中. (56认同)
  • 为什么你期望在开始......结束之前评估while修饰符?这就是do..while循环应该起作用的方式.为什么你会"很高兴永远不会再看到这个成语?" 它出什么问题了?我糊涂了. (10认同)
  • 由Wayback Machine提供:http://web.archive.org/web/20080206125158/http://archive.jvoorhis.com/articles/2007/06/13/ruby-hidden-do-while-loop (5认同)
  • 开始...结束看起来像一个块,同样{...}.它没有错. (2认同)

Blo*_*ard 102

像这样:

people = []

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

参考:Ruby的Hidden do {} while()循环

  • 您可以使用`until info.empty?`而不是`而不是info.empty?`. (9认同)

And*_*ewR 45

这个怎么样?

people = []

until (info = gets.chomp).empty?
  people += [Person.new(info)]
end
Run Code Online (Sandbox Code Playgroud)

  • 但这不是"做......而是"循环.:) (23认同)
  • @Blorgbeard,一个do..while循环总是运行一次,然后计算它是否应该继续运行.传统的while/until循环可以运行0次.这不是一个巨大的差异,但它们是不同的. (18认同)
  • @Scott,这是真的 - 我只是意味着这个代码相当于OP,即使它不使用do/while.虽然真的,这个代码在条件中完成了一半循环的"工作",所以它不是一个传统的while循环 - 如果条件不匹配,一些工作仍然完成. (5认同)
  • 不错,更优雅. (4认同)
  • 但在这种情况下它会做同样的事情,除非我弄错了 (4认同)

小智 11

这是hubbardr与博客死链接的全文文章.

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)
Run Code Online (Sandbox Code Playgroud)

乍一看,我假设while修改器将在内容之前进行评估begin...end,但事实并非如此.注意:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil
Run Code Online (Sandbox Code Playgroud)

正如您所料,循环将在修饰符为true时继续执行.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil
Run Code Online (Sandbox Code Playgroud)

虽然我很高兴再也看不到这个成语,但是begin...end非常强大.以下是记忆没有参数的单线方法的常用习语:

def expensive
  @expensive ||= 2 + 2
end
Run Code Online (Sandbox Code Playgroud)

这是一个丑陋但快速的方法来记忆更复杂的东西:

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
Run Code Online (Sandbox Code Playgroud)


Ste*_*ing 10

这现在正常工作:

begin
    # statment
end until <condition>
Run Code Online (Sandbox Code Playgroud)

但是,它可能在将来删除,因为该begin陈述是违反直觉的.见:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745

Matz建议这样做:

loop do
    # ...
    break if <condition>
end
Run Code Online (Sandbox Code Playgroud)


小智 6

从我收集的内容来看,Matz不喜欢这个结构

begin
    <multiple_lines_of_code>
end while <cond>
Run Code Online (Sandbox Code Playgroud)

因为,它的语义不同于

<single_line_of_code> while <cond>
Run Code Online (Sandbox Code Playgroud)

因为第一个构造在检查条件之前首先执行代码,第二个构造在执行代码之前首先测试条件(如果有的话).我认为Matz更喜欢保留第二个结构,因为它匹配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
Run Code Online (Sandbox Code Playgroud)

我不知道这些建议是否会用其他语言进行解析.但在任何情况下,我都倾向于保持从左到右的执行以及语言的一致性.