Rubyのピリオド2つの意味 【Ruby on Rails超入門】

2019年1月14日月曜日

プログラミング

Rubyのピリオド2つの意味

こんにちは、財前航介です。

今日は、Rubyでよく見る、ピリオド2つの意味について学んでいきましょう。

例えば、以下のようなものですね:

1..10

とか

“a”..”g”

みたいな…


一言で言うと、このピリオド2つは「範囲」を表しています。

ただ、この使い方には、いくつか注意点があります。

それでは、このピリオド2つの意味と使い方について、詳しく見ていきましょう。

Rubyのピリオド2つの意味【Rangeクラス】

Rubyのピリオド2つの意味【Rangeクラス】

ピリオド2つはRangeクラスのインスタンスを返す


1..10

とか

“a”..”g”

という書き方は文法的に何を意味しているのかと言えば、
Rangeクラスのインスタンスを、一種のリテラルで定義した書き方です。

どういう事かというと…


リテラルとは、たとえば

str = “hello world”

などと書いたとき、”hello world”の部分が、Stringクラスのオブジェクトをリテラルで定義していますね。


上記のストリングの例は、下記のものと同じ意味です。

str = String.new("hello world")

newメソッドを用いれば、明示的にインスタンス生成ができますが、結果は上記の暗黙のリテラルコンストラクタを用いたときと全く一緒です。


では、「1..10」を、明示的に書くと、どのようになるのでしょうか。

実は、これは以下の記述と同じ意味なのです。

Range.new(1, 10)


つまり、
1..10
という書き方は、Rangeというクラスのインスタンスを生成して戻り値として返すような、暗黙のコンストラクタを呼び出しているのです。


ちなみに、
"a".."g"
などのように文字列の範囲を定義した場合も、下記と同じ意味になります。

Range.new("a", "g")


Rangeクラス


ピリオド2つで表された記載が、Rangeというクラスのインスタンスを生成していることは分かったとして、では、このRangeクラスとはどういったものなのでしょうか。

Rangeとは、数字や文字列の「ここからここまで」という範囲を表すクラスです。

たとえば、
1..10

Range.new(1, 10)
と書いたときに戻り値として返ってくるRangeインスタンスは、
「1から10まで」
という数字の範囲を表しています。


Rangeクラスの「to_a」メソッドを使うと、配列に変換された要素を得ることができるので、分かりやすいと思います。

下記の例を見てみてください。

# Rangeインスタンスを変数rに格納
r = 1..10

# rを配列に変換して出力
p r.to_a

結果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


1から10までの数字が格納された配列に変換されたことが、お分かり頂けたでしょうか。


同様に、
"a".."g"
のように文字列2つを引数として宣言した場合は、
「"a"から"g"まで」
というアルファベットの範囲を表します。

# Rangeインスタンスを変数rに格納
r = "a".."g"

# rを配列に変換して出力
p r.to_a

結果:
["a", "b", "c", "d", "e", "f", "g"]

文字列の場合も、数字と同じように範囲を表していることが分かりますね。


ピリオド2つを用いると繰り返し処理を簡潔に書ける


なぜRangeクラスのnewメソッドを用いて、明示的にインスタンス生成をしないのかといえば、ピリオド2つの方が記述が短くて済むからですね。

そして、わざわざ短縮形が用意されているということは、RangeクラスというものがRubyにおいて頻繁に使われるクラスであるということを表しています。
よく使うから、短縮形を用意してあるんですね。

一体、どういった場合に使うのでしょうか。


Rangeクラスの効果が最も発揮されるのは繰り返し処理においてです。

たとえば、以下のような書き方ができます。

(1..10).each { |i| puts i**2 }

結果:
1
4
9
16
25
36
49
64
81
100

この例では、1から10までの数字それぞれの2乗の値が結果として出力されていますね。

Rangeクラスに用意されている「each」メソッドを用いると、「each」メソッドの引数として渡されているブロックの中の処理を、範囲内の各値ごとに実行できるのです。

縦棒「|」記号で囲まれた変数に、範囲内の値を一つずつ代入し、ブロック内の処理を実行していくので、この場合では「 i の2乗」を順番に出力していますね。


また、上記の{}で囲まれたブロックは、以下のように「do」「end」で括っても同じ意味になりますね。

(1..10).each do |i|
  puts i**2
end

結果:
1
4
9
16
25
36
49
64
81
100

また、上記の処理は、for文を用いて以下のように書くこともできます。

for i in 1..10 do
  puts i**2
end

結果:
1
4
9
16
25
36
49
64
81
100

また、for文における「do」は省略することができるので、以下の記述も同じ意味になります。

for i in 1..10
  puts i**2
end

結果:
1
4
9
16
25
36
49
64
81
100


色々書き方があって困ってしまいますね。

個人的には、以下のように、「each」メソッドを用いて書くのがカッコイイと思っています。

(1..10).each do |i|
  puts i**2
end


どの書き方を用いるにしろ、コンパクトに記述できるのが、Ruby言語の素晴らしいところですね。

他のプログラミング言語であれば、以下のように記述する必要がある場合もあるでしょう。

//他言語であれば、こんな感じ?
for ( int i=1, i<=10, i++ ){
  print i*i;
}

上記はあくまでイメージですが、Rubyの書き方の方が、Rangeオブジェクトのメソッドとしてループが完結している辺り、クールに感じます。


ピリオド2つの範囲をレシーバーとして使うときは、括弧で括ろう!

ピリオド2つの範囲をレシーバーとして使うときは、括弧で括ろう!

さて、Rangeクラスを用いると、ループの書き方がクールになることが分かったところで、注意点を見てみましょう。

なんてことはないのですが、ピリオド2つを使って生成したRangeインスタンスのメソッドを用いるときは、範囲の記述を括弧()で括る必要があるということです。

たとえば上記で用いた例をもう一度見てみましょう。

(1..10).each { |i| puts i**2 }


ここでは、
1..10.each { |i| puts i**2 }
のように記述せず、
1..10
を括弧()で括って、
(1..10).each { |i| puts i**2 }
という風に記述していますね。


勘の良い方はお気づきかもしれませんが、これは、
1..10.each
という風に書くと、
1..(10.each)
という切れ目であると判断されてしまうためです。

つまり、10という数値のメソッドとして「each」メソッドを呼び出そうとするのです。

数値である10には、「each」などというメソッドはありませんから、エラーになってしまいます。

つまり、ピリオド2つを用いて定義したRangeインスタンスのメソッドを用いたいときは、その範囲を括弧()で括って、その後に「.each」というようなメソッド呼び出しの記述をする必要があります。


Rubyにおけるピリオド3つは、最後の値を含まない範囲

Rubyにおけるピリオド3つは、最後の値を含まない範囲

さてピリオド2つの意味は分かったとして、
Rubyにおいては、
ピリオドが3つ連続で配置されるような記述を目にすることがあります。

1...10
とか、
"a"..."g"
のような記述です。

これもピリオド2つの時とほとんど同じ意味なのですが、

「ピリオド3つは、最後の値を含まない」

という違いがあります。


実際に動かした結果を見てみましょう。

p (1...10).to_a

結果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

どうでしょうか。
ほとんど同じに見えますが、結果の最後に「10」が含まれていませんね。

違いはこれだけです。

ピリオド2つでも、ピリオド3つでも、基本的には使い方は一緒なので、
「ピリオド3つは、最後の値を含まない」
とだけ覚えておきましょう。


まとめ:
Rubyのピリオド2つの意味を理解して、クールにループ処理を書こう!

Rubyのピリオド2つの意味を理解して、クールにループ処理を書こう!

如何でしたでしょうか?

Rubyは、日本人であるまつもとゆきひろ氏が、「楽しんでプログラミングできる」言語を目指して開発した言語です。

他言語に比べて、とても記述が簡潔に済みますし、ループがRangeというオブジェクトのメソッドとして完結している辺り、自分はカッコイイし、書いていて楽しいと感じます。


Ruby言語そのものも洗練された素晴らしい言語ですが、やはりRubyの威力を語るには、Ruby on Railsというフレームワークに触れないわけには行けません。

Web開発を圧倒的に効率化するRuby on Railsについて興味がある方は、是非以下の記事もご参照ください: