Почему (1..5).each выполняет итерацию по 1,2,3,4,5, но (5..1) не будет? Вместо этого он возвращает диапазон.
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) не будет? Вместо этого он возвращает диапазон.
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
Самый простой способ сделать это - использовать downto
5.downto(1) do |i| puts i end
Диапазоны используют <=>, чтобы определить, закончилась ли итерация; 5 <=> 1 == 1 (больше, чем), поэтому оно выполняется до его начала. Даже если они этого не сделали, диапазон повторяется с использованием succ; 5.succ 6, все еще не повезло. Диапазон step не может быть отрицательным, поэтому он не будет работать.
Он возвращает диапазон, потому что each возвращает то, на что он был вызван. Используйте downto, если это сама функциональность, которую вы ищете, иначе приведенный выше ответ на ваш фактический вопрос о "почему".
Вы можете легко расширить класс Range, в частности каждый метод, чтобы он совместим как с восходящими, так и с нисходящими диапазонами:
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, это просто простая математическая модель: диапазон, начинающийся с 5 и заканчивающийся на 1, пуст. Итерации нет.
Потому что Ruby делает только то, что он сказал, а не то, что вы означают.
Невозможно определить, хотите ли вы перейти в обратном направлении (т.е. 5, 4, 3, 2, 1) или хотите ли вы только цифры, начинающиеся с 5, которые меньше или равны 1. Теоретически возможно, что кто-то может захотеть последнего, и потому, что Ruby не может сказать, чего вы действительно хотите, он пойдет с последним.