Подтвердить что ты не робот

Почему Range не работает при спуске?

Почему (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
4b9b3361

Ответ 1

Самый простой способ сделать это - использовать downto

5.downto(1) do |i| puts i end

Ответ 2

Диапазоны используют <=>, чтобы определить, закончилась ли итерация; 5 <=> 1 == 1 (больше, чем), поэтому оно выполняется до его начала. Даже если они этого не сделали, диапазон повторяется с использованием succ; 5.succ 6, все еще не повезло. Диапазон step не может быть отрицательным, поэтому он не будет работать.

Он возвращает диапазон, потому что each возвращает то, на что он был вызван. Используйте downto, если это сама функциональность, которую вы ищете, иначе приведенный выше ответ на ваш фактический вопрос о "почему".

Ответ 3

Вы можете легко расширить класс 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}

Ответ 4

Это даже не имеет никакого отношения к Ruby, это просто простая математическая модель: диапазон, начинающийся с 5 и заканчивающийся на 1, пуст. Итерации нет.

Ответ 5

Потому что Ruby делает только то, что он сказал, а не то, что вы означают.

Невозможно определить, хотите ли вы перейти в обратном направлении (т.е. 5, 4, 3, 2, 1) или хотите ли вы только цифры, начинающиеся с 5, которые меньше или равны 1. Теоретически возможно, что кто-то может захотеть последнего, и потому, что Ruby не может сказать, чего вы действительно хотите, он пойдет с последним.