これまでに説明の中で, Rubyのリファレンスマニュアルを何度か取り上げてきました. その最初のページに「組み込みクラス」という項目が挙げられています. これまで,あえて触れていませんでしたが, そのページを参照してみると, Integer(整数),String(文字列),Array(配列),Hash(ハッシュ)など, これまでに扱ったオブジェクトに関連する「クラス」を始め, 様々な「クラス」があることが分かります. ここでは,「クラス」という概念について,ごく簡単に説明します.
もくじ
クラスとは
Rubyのオブジェクトは全て何らかのクラスに属します. 整数オブジェクトは整数クラス,文字列オブジェクトは文字列クラス, 配列オブジェクトは配列クラスに属するオブジェクトです. 「1」と「2」は同じ整数クラスのオブジェクトです. 一方,「"This is a string"」と「[1,2,3]」は, 文字列と配列という別々のクラスのオブジェクトです.
要するに,まずクラスとは,オブジェクトの種類を規定するものであるといえます. 同じクラスのオブジェクトは,同じ構造のデータと同じメソッドをもっています. 言い換えれば,クラスとは, そのクラスに属するオブジェクトがどのような構造と機能を備えているか決める, オブジェクトの仕様書,設計書であるといえます.
なお,一般にオブジェクト指向の世界では,クラスに属するオブジェクトのことを, そのクラスのインスタンス(instance;事例)とよびます. クラスがオブジェクトの種類を規定していて, そのクラスに属している具体的なオブジェクトの実例をインスタンスとよぶわけです. 各インスタンス(オブジェクト)は,それぞれが別々の実体をもちます. インスタンスは,プログラムを実行していく中で, 必要になった時点で,クラスの仕様にしたがって,作りだされます. インスタンスを作るには,一般的には,後述のnewメソッドを利用します. これまでにでてきた整数,文字列,配列のように, 明示的にnewを使わなくてもインスタンスを生成できる場合もあります.
Rubyでは,オブジェクトの属するクラスを, classというメソッドで,調べることができます.
p "文字列".class # ==> String
p [0,1,2].class # ==> Array
p 1.class # ==> Fixnum
p 10000000000000.class # ==> Bignum
ここで,整数「1」と「10000000000000」のクラスが「Integer」ではなく, 「Fixnum」と「Bignum」になっていますが, これらはいずれも「Integer」クラスのサブクラスです. 逆に「Integer」クラスは,「Fixnum」と「Bignum」の スーパークラスとよばれます. サブクラスは,スーパークラスのデータ構造やメソッドを引き継ぎます. つまり「1」と「10000000000000」は異なるクラスのインスタンスですが, いずれも「Integer」の一種です.
詳しくは述べませんが,ここで挙げた例のように,クラスには階層関係があります. これは,たとえば,「生物」が「動物」,「植物」などに大別され, さらに「動物」は「無脊椎動物」と「脊椎動物」に分けられる, などというように,大きな種のくくりがさらに細かく分類されるようなものです.
「Fixnum」と「Bignum」の例に戻ると,「Integer」がこれらに細分類されるのは, Rubyの内部で小さな整数と大きな整数のデータ表現が異なるためです. 整数を使ったプログラムを作成する上で,これらを区別しなければならないことは, まずありません.
クラスメソッド
これまで利用してきたメソッドとして,まず オブジェクトのメソッドがありました. これを,正式にはインスタンスのメソッド, インスタンスメソッドといいます. インスタンスメソッド以外には,レシーバのオブジェクトが省略された 関数的メソッドがありました. Rubyには,これら以外に, クラスメソッドとよばれるメソッドがあります. クラスメソッドは,そのクラスに特有な処理を行うメソッドですが, インスタンスに対して処理を行うメソッドではありません. クラスメソッドは,次の形式で起動します.
クラス名.メソッド # 引数がない場合
クラス名.メソッド(引数1,引数2,...) # 引数がある場合
代表的なクラスメソッドとして, クラスのインスタンスを新たに生成するnewが挙げられます. 一部の例外を除いて,ほとんどのクラスに,このクラスメソッドがあります. なお,既に述べた通り, 整数,文字列,配列など,newメソッドを明示的に使わなくても, インスタンスが生成できるクラスもあります. また,new以外のメソッドでインスタンスを生成するクラスもあります. 詳しくは,リファレンスマニュアルを参照して下さい.
クラスの定義と拡張
Rubyには,はじめから便利なクラスが豊富に用意されています. それらを組み合わせて用いるだけでも,もちろんプログラムを作ることができます. また必要に応じて,新しいクラスを定義したり, 既存のクラスに手を加えて,新しいメソッドを追加することもできます. ここでは,既存のクラスを拡張する方法について述べます. 新しくクラスを定義する方法については, Rubyの参考書などを参照して下さい.
サンプルコード
次のプログラムは,文字列クラスに新しいインスタンスメソッドを追加した例を示しています.
#
# 文字列クラスに新しいインスタンスメソッドを追加するテスト
#
class String
# selfの空白で区切られた単語数をカウントする.
def wc()
return self.split.size
end
# selfの空白で区切られた各単語の中に引数keyが現われる位置を
# 配列にして返す.
def indices(key)
ary = [] # ary = Array.new でも可
words = self.split
words.each do |w|
ary.push(w.index(key))
end
return ary
end
# selfの連続した空白文字を一文字にする
def strip_redundant_spaces!()
return self.squeeze!(" ")
end
end
# 新しいメソッドを試す
str = "this is a test string"
str.strip_redundant_spaces!
p str # ==> "this is a test string"
p str.wc # ==> 5
p str.indices("is") # ==> [2, 0, nil, nil, nil]
[extend_string.rb]
クラスへのインスタンスメソッドの追加
既存のクラスに新しいメソッドを追加するには,次のように 「class...end」内でメソッドを定義します.
class クラス名
# 新しい定義の追加をここに記述する.
end
なお,既存のメソッドと同じ名前を使ってメソッドの定義を行うと, そのメソッドの定義を書き換えることになります.
self
インスタンスメソッドの定義では, そのメソッドが起動されたときのレシーバであるインスタンス自身は, selfという特別な変数で表されます. 上のサンプルにも例がある通り, インスタンスメソッドの中で,自分自身のメソッドを起動するときは, レシーバがselfとなるわけです. なお,selfは省略することも可能です (ここでは説明しませんが,省略しないといけない場合もあります).