正如@Tobias 已经回答了您的问题,我想花一些时间来建议您如何使您的代码更像 Ruby。
首先,虽然您可以使用while
oruntil
循环,但我建议您主要依靠Kernel#loop方法来编写大多数循环。loop
这只会导致循环在' 块内继续,直到break
遇到关键字1。它很像while true
or until false
(在某些语言中常用),但我认为它读起来更好。更重要的是,使用loop
保护其块内的计算免受窥探。(有关这一点的示例,请参见下面的其他注意事项部分。)
您也可以通过执行or退出loop
' 块,但通常您会使用. return
exit
break
我的第二个主要建议是,对于此类问题,您使用 acase statement
而不是if/elsif/else/end
构造。让我们首先使用范围来做到这一点。
使用带范围的 case 语句
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
guess_count += 1
case gets.chomp.to_i
when my_num
puts "you got it!"
break
when 0..my_num-1
puts "higher"
else
puts "lower"
end
end
这里有几点需要注意。
- 我使用
print
而不是puts
这样,用户将在与提示相同的行上输入他们的响应。
guess_count
无论用户的响应如何,都会递增,因此可以在执行 case 语句之前完成。
- 无需将用户的响应 (
gets.chomp.to_i
) 分配给变量。
- case 语句将值与适当的大小写相等方法
===
进行比较。
关于最后一点,这里我们将一个整数 ( gets.chomp.to_i
) 与另一个整数 ( my_num
) 和一个范围进行比较(0..my_num-1)
。在第一种情况下,Integer#===
使用 ,相当于Integer#==
。对于范围,使用Range#===方法。
例如,假设my_num = 100
和gets.chomp.to_i #=> 50
case 语句如下所示。
case 50
when 100
puts "you got it!"
break
when 0..99
puts "higher"
else
puts "lower"
end
在这里,我们发现100 == 50 #=> false
和(0..99) === 50 #=> true
,所以puts "higher"
显示。(0..99) === 50
返回true
,因为整数(右侧===
)被范围(左侧)覆盖。这与 不一样50 === (0..90)
,后者松散地读作“(0..99)
是”的成员,50
因此false
返回。
这里有几个例子,说明如何使用 case 语句来发挥优势,因为它们依赖于三等式方法。
case obj
when Integer
obj + 10
when String
obj.upcase
when Array
obj.reverse
...
end
case str
when /\A#/
puts "A comment"
when /\blaunch missiles\b/
big_red_button.push
...
end
对spaceship 运算符使用 case 语句 <=>
spaceship 运算符由 Ruby 的Array#sort和Enumerable#sort方法使用,但还有其他用途,例如在 case 语句中。这里我们可以使用Integer#<=>来比较两个整数。
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
case gets.chomp.to_i <=> my_num
when 0
puts "you got it!"
break
when -1
puts "higher"
else # 1
puts "lower"
end
end
在其他应用程序中,宇宙飞船运算符可能用于比较字符串(String#<=>)、数组(Array#<=>)、Date
对象(Date#<=>)等等。
使用哈希
哈希通常可以用作case statements
. 在这里,我们可以编写以下内容。
response = { -1=>"higher", 0=>"you got it!", 1=>"lower" }
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
guess = gets.chomp.to_i
puts response[guess <=> my_num]
break if guess == my_num
end
这里我们需要gets.chomp.to_i
两次的值,所以我把它保存到一个变量中。
其他注意事项
假设我们编写以下内容:
i = 0
while i < 5
i += 1
j = i
end
j #=> 5
j
在循环之后发现等于5
。
如果我们改为使用loop
:
i = 0
loop do
i += 1
j = i
break if i == 5
end
j #=> NameError (undefined local variable or method 'j')
虽然while
和loop
都可以访问i
, 但是loop
将在其块中创建的局部变量的值限制在块中。那是因为块创建了一个新的范围,这是一种很好的编码习惯。while
并且until
不要使用块。我们通常不希望循环之后的代码能够访问在循环中创建的局部变量,这是支持andloop
的原因之一。while
until
最后,关键字break
也可以与由 . 返回的参数一起使用loop
。例如:
def m
i = 0
loop do
i += 1
break 5*i if i == 10
end
end
m #=> 50
或者
i = 0
n = loop do
i += 1
break 5*i if i == 10
end
n #=> 50
1. 如果您检查文档,Kernel#loop
您会发现break
从loop
's 块内执行等同于引发StopIteration
异常。