Open1
【ruby】範囲オブジェクトRangeのややこしさ
小数のややこしさ
(1..2) == (1..2.0) # => true
(1..2).eql? (1..2.0) # => false
eql?
と==
の挙動が違う。まあこれは別言語・別クラスでもあることですね。
n = 2.5
p 1..n # => 1..2.5
(1..n).each { |i| p i }
# => 1
# => 2
# 終了
範囲は1 ~ 2.5
だが、each
でp
してみると1
と2
だけです。
=> step
のデフォルトが1
になっています。
=> 健全ではないですが、実質的に「終点の丸め処理」と同じ挙動です。
n = 10.5
(1..n).step(0.5).each { |i| p i }
(1..n).step(5).each { |i| p i }
# 結果は以下
step
を変更することで、任意の小数・倍数も扱うことができます。
stepのややこしさ
Range
クラスからは少し離れた話になりますが・・・
先ほど見たstep
は「各ステップの大きさ」を表していました。
しかし、以下の例では「ループの上限」を指定しています。
「各ステップの大きさ」を表すには、引数を2つ与えなければなりません。
2.step(5){|n| p n}
# => 2
# => 3
# => 4
# => 5
1.1.step(1.5, 0.1) {|n| p n}
# => 1.1
# => 1.2
# => 1.3
# => 1.4
# => 1.5
この違いは「クラスの違い」です。
Rangeクラスに使うときは「ステップの大きさ」のみを指定できます。
一方で、Numeric
クラスのstep
が、この章で触れたものです。
(Numeric
はIntefer
, Float
, Rational
, Complex
などの基底クラスです。)