有一个"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循环:

people = []


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

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

不幸的是,Ruby中似乎不存在这种类型的循环。谁能提出一个更好的方法来做这件事?

277121 次浏览

我在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…结束,但事实并非如此。观察:

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

虽然我很高兴再也不会看到这个习语,但开始吧……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

Jeremy Voorhis。这里的内容是复制的,因为它似乎是从原始站点删除的。副本也可以在Web ArchiveRuby Buzz论坛中找到。——蜥蜴比尔

是这样的:

people = []


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

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

这个怎么样?

people = []


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

这是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

正如您所期望的那样,当修饰符为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
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

谨慎:

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

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

以下是2005年11月23日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维基也有类似的故事:

在2005年11月期间,Ruby的创建者松本幸弘(Yukihiro Matsumoto)后悔了这个循环特性,并建议使用Kernel#loop。

现在可以正常工作了:

begin
# statment
end until <condition>

但是,它可能会在将来被删除,因为begin语句是违反直觉的。看:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745

Matz (Ruby的创造者)建议这样做:

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

据我所知,马茨不喜欢这种说法

begin
<multiple_lines_of_code>
end while <cond>

因为它的语义是不同的

<single_line_of_code> while <cond>

,因为第一个构造在检查条件之前先执行代码, 第二个构造在执行代码(如果有的话)之前先测试条件。我认为Matz更喜欢保留第二个结构,因为它匹配if语句的一行结构 我从来不喜欢第二个结构,即使是if语句。在所有其他情况下,计算机 从左到右执行代码(例如;||和&&)从上到下。人类从左到右阅读代码 全面。< / p >

我建议使用以下结构:

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
我不知道这些建议是否会与语言的其余部分一起解析。但是无论如何 我更喜欢保持从左到右的执行,以及语言的一致性