(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
それを行う最も簡単な方法は、
5.downto(1) do |i| puts i end
範囲は<=>
を使用して、反復が終了したかどうかを判別します。 5 <=> 1 == 1
(より大きい)なので、開始する前に実行されます。そうしなかったとしても、範囲はsucc
を使用して繰り返されます。 5.succ
は6
ですが、まだ運が悪いです。範囲のstep
を負にすることはできないため、それも機能しません。
each
は呼び出されたものを返すため、範囲を返します。探している機能自体である場合はdownto
を使用します。それ以外の場合は、上記が「理由」に関する実際の質問に答えます。
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とは実際には何の関係もありません。単純な基本的な計算です。つまり、5
で始まり1
で終わる範囲は空です。繰り返すことは何もありません。
Rubyは言われたことだけを行い、あなたがしたことはしません 平均 。
逆にしたいか(つまり、5、4、3、2、1)、または5から始まる1以下の数字だけが本当に必要かどうかはわかりません。理論的には誰かが後者が必要な場合があります。Rubyは本当に必要なものがわからないため、後者を使用します。