【发布时间】:2012-02-08 00:21:44
【问题描述】:
为什么(1..5).each 会迭代1,2,3,4,5,而(5..1) 不会?而是返回 Range。
1.9.2p290 :007 > (1..5).each do |i| puts i end
1
2
3
4
5
=> 1..5
1.9.2p290 :008 > (5..1).each do |i| puts i end
=> 5..1
【问题讨论】:
为什么(1..5).each 会迭代1,2,3,4,5,而(5..1) 不会?而是返回 Range。
1.9.2p290 :007 > (1..5).each do |i| puts i end
1
2
3
4
5
=> 1..5
1.9.2p290 :008 > (5..1).each do |i| puts i end
=> 5..1
【问题讨论】:
您可以轻松地扩展Range 类,尤其是each 方法,使其与升序和降序范围兼容:
class Range
def each
if self.first < self.last
self.to_s=~(/\.\.\./) ? last = self.last-1 : last = self.last
self.first.upto(last) { |i| yield i}
else
self.to_s=~(/\.\.\./) ? last = self.last+1 : last = self.last
self.first.downto(last) { |i| yield i }
end
end
end
然后,下面的代码将按照您的预期执行:
(0..10).each { |i| puts i}
(0...10).each { |i| puts i}
(10..0).each { |i| puts i}
(10...0).each { |i| puts i}
【讨论】:
因为 Ruby 只做它被告知的事情,而不是你 mean 的事情。
它无法判断您是否要反向(即5、4、3、2、1),或者您是否真的只想要从5开始小于或等于1的数字。理论上是可能有人想要后者,因为 Ruby 无法说出你真正想要什么,所以它会选择后者。
【讨论】:
这甚至与 Ruby 没有任何关系,只是简单的基本数学运算:以 5 开头并以 1 结尾的范围是空的。没有什么可以迭代的。
【讨论】:
<=>,只要求左值。
succ 和 <=>,这还不够向下迭代。
范围使用<=> 来确定迭代是否结束; 5 <=> 1 == 1(大于),所以它在开始之前就完成了。即使他们没有,范围使用succ 进行迭代; 5.succ 是 6,仍然不走运。范围的step 不能为负数,因此也不起作用。
它返回范围,因为each 返回它被调用的内容。如果您正在寻找功能本身,请使用downto,否则以上内容回答了您关于“为什么”的实际问题。
【讨论】:
最简单的方法是使用 downto
5.downto(1) do |i| puts i end
【讨论】:
x = 5.downto(1) 并将 x 作为变量传递。
.each
Numeric#step 更灵活一点;它也需要一个步长,而Integer#downto 只需要一个限制。