範囲は、2つの値の間の区間を表します。
範囲をサポートする最も一般的な型は、IntegerとStringです。
範囲は、コレクションを手早く作る、文字列を切り出す、ある値が範囲に含まれるか調べる、繰り返し処理するなど、さまざまなことに使えます。
範囲は、範囲演算子..または...を使って作ります(それぞれ終端を含むものと含まないものに対応します)。
1..5 # => 1..5
1...5 # => 1...5
(1..5).to_a # => [1, 2, 3, 4, 5]
(1...5).to_a # => [1, 2, 3, 4]
範囲演算子が2つあるのは、終端の値を含む範囲と含まない範囲の両方を作れるようにするためです。これは例えば、0から始まるインデックスを扱うときに便利です。
範囲は、Rangeのイニシャライザーを使って作ることもできます。
Range.new(1, 5) # A range containing 1, 2, 3, 4, 5
Rubyで範囲演算子..や...を使って範囲を作り、その範囲に対してメソッドを呼び出したいときは、範囲を括弧で囲む必要があります。
そうしないと、メソッドは範囲演算子の2番目の引数に対して呼び出されてしまうからです。
(1..5).sum # => 15
1..5.sum # => Error: undefined method `sum' for 5:Integer (NoMethodError)
文字列を切り出したいときは、範囲演算子を使って部分文字列を取り出せます。 つまり、部分文字列の開始インデックスと終了インデックスで範囲を作ります。
"Hello World"[0..4] # => "Hello"
"Hello World"[6..10] # => "World"
負のインデックスを使うと、文字列の末尾から部分文字列を取り出すこともできます。
"Hello World"[-5..-1] # => "World"
"Hello World"[6..-4] # => "Wo"
範囲には、範囲を扱うためのメソッドがいくつか用意されています。 例えば、範囲内のすべての値の合計を求めたり、ある値が範囲に含まれるか調べたりするのに使えます。
| メソッド | 説明 | 例 |
|---|---|---|
sum |
範囲内のすべての値の合計を返します | (1..5).sum # => 15 |
size |
範囲のサイズを返します | (1..5).size # => 5 |
include? |
範囲に指定した値が含まれていればtrue、そうでなければfalseを返します |
(1..5).include?(3) # => true |
範囲には、終わりがないものと始まりがないものがあります。
終端や始端のない範囲では、開始値または終了値がnilになりますが、範囲を定義するときにはそのnilを省略できます。
始端や終端のない範囲は、例えば文字列を先頭から、あるいは末尾まで切り出したいときに便利です。
"Hello World"[0..] # => "Hello World"
"Hello World"[4..] # => "o World"
"Hello World"[..5] # => "Hello "
コレクションに対して使わない場合、終端のない範囲は、注意して使わないと終わりのない繰り返しを引き起こすことがあります。
範囲には文字列も使えて、2つの文字列の間にある文字列の区間を取得できます。 特定の文字列を使うと動作が少し予想外になることがあるので、注意して使ってください。
"aa".."az".to_a # => ["aa", "ab", "ac", ..., "az"]
Rubyでは、独自のオブジェクトを範囲に使えます。 そのための条件は、オブジェクトが次のものを実装していることです。
Comparableモジュールをincludeしていることsuccメソッドを実装していること<=>メソッドを実装していることこれらのメソッドによって、範囲がオブジェクトを繰り返し処理したり、範囲内のオブジェクトを比較したりできるようになります。
class Foo
include Comparable
attr_reader :value
def initialize(value)
@value = value
end
def succ
Foo.new(value + 1)
end
def <=>(other)
value <=> other.value
end
end
(Foo.new(1)..Foo.new(5))
# => #<Foo:0x7f3552bebe70 @value=1>, #<Foo:0x7f3552bebe50 @value=2>, #<Foo:0x7f3552bebe40 @value=3>, #<Foo:0x7f3552bebe30 @value=4>, #<Foo:0x7f3552bebe20 @value=5>