可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using this code to let the user enter in names while the program stores them in an array until they enter an empty string (they must press enter after each name):
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
This code would look much nicer in a do ... while loop:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
In this code I don't have to assign info to some random string.
Unfortunately this type of loop doesn't seem to exist in Ruby. Can anybody suggest a better way of doing this?
回答1:
CAUTION:
The begin <code> end while <condition>
is rejected by Ruby's author Matz. Instead he suggests using Kernel#loop
, e.g.
loop do
# some code here
break if <condition>
end
For more details please refer to: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 (or via Wayback), and this wiki: http://rosettacode.org/wiki/Loops/Do-while#Ruby
回答2:
I found the following snippet while reading the source for Tempfile#initialize
in the Ruby core library:
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)
At first glance, I assumed the while modifier would be evaluated before the contents of begin...end, but that is not the case. Observe:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
As you would expect, the loop will continue to execute while the modifier is true.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
While I would be happy to never see this idiom again, begin...end is quite powerful. The following is a common idiom to memoize a one-liner method with no params:
def expensive
@expensive ||= 2 + 2
end
Here is an ugly, but quick way to memoize something more complex:
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
Originally written by Jeremy Voorhis. The content has been copied here because it seems to have been taken down from the originating site. Copies can also be found in the Web Archive and at Ruby Buzz Forum. -Bill the Lizard
回答3:
Like this:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Reference: Ruby's Hidden do {} while () Loop
回答4:
How about this?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
回答5:
Here's the full text article from hubbardr's dead link to my blog.
I found the following snippet while reading the source for Tempfile#initialize
in the Ruby core library:
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)
At first glance, I assumed the while
modifier would be evaluated before the contents of begin...end
, but that is not the case. Observe:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
As you would expect, the loop will continue to execute while the modifier is true.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
While I would be happy to never see this idiom again, begin...end
is quite powerful. The following is a common idiom to memoize a one-liner method with no params:
def expensive
@expensive ||= 2 + 2
end
Here is an ugly, but quick way to memoize something more complex:
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
回答6:
This works correctly now:
begin
# statment
end until <condition>
But, it may be remove in the future, because the begin
statement is counterintuitive. See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz recommended doing it this way:
loop do
# ...
break if <condition>
end
回答7:
From what I gather, Matz does not like the construct
begin
<multiple_lines_of_code>
end while <cond>
because, it's semantics is different than
<single_line_of_code> while <cond>
in that the first construct executes the code first before checking the condition,
and the second construct tests the condition first before it executes the code (if ever). I take it Matz prefers to keep the second construct because it matches one line construct of if statements.
I never liked the second construct even for if statements. In all other cases, the computer
executes code left-to-right (eg. || and &&) top-to-bottom. Humans read code left-to-right
top-to-bottom.
I suggest the following constructs instead:
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
I don't know if those suggestions will parse with the rest of the language. But in any case
I prefere keeping left-to-right execution as well as language consistency.
回答8:
a = 1
while true
puts a
a += 1
break if a > 10
end
回答9:
Here's another one:
people = []
1.times do
info = gets.chomp
unless info.empty?
people += [Person.new(info)]
redo
end
end
回答10:
ppl = []
while (input=gets.chomp)
if !input.empty?
ppl << input
else
p ppl; puts "Goodbye"; break
end
end