Rubyのクラスの基本についてです。以前書いたメソッドと、変数・定数について関係してるところもあるのでリンク貼っておきます。
クラスとは
Rubyは全てのデータがオブジェクトです。また、オブジェクトは例外なくなんらかのクラスに属しています。オブジェクトがどのクラスに属しているのか確認するには.class
メソッドを使用します。
"hoge".class #=> String 100.class #=> Fixnum [1, 2, 3].class #=> Array false.class #=> FalseClass
オブジェクトがあるクラスのインスタンスかどうかを判断するには.instance_of?(klass)
メソッドを使います。
ary = Array.new() p ary.instance_of?(Array) #=>true p ary.instance_of?(String) #=>false
オブジェクトに割当られている重複しないID(整数)を確認するには.object_id
メソッドを使います。
"hoge".object_id => 70283213979680 "fuga".object_id => 70283211279280
クラスを作る
クラスを作るための基本的な構文は次の通りです。クラス名は必ず大文字で初めなければいけません。
class クラス名 クラスの定義 end
initializeメソッド
クラスのインスタンスをを生成するには.new()
メソッドを使います。initialize メソッドがある場合は、new メソッドを使うと必ず呼ばれます。イメージ的にはJavaのコンストラクタです。次の例ではデフォルト引数が指定されていますが、引数無しでも問題ありません。
class Foo def initialize(str="hoge") p str end end bar = Foo.new("fuga") #=>"fuga"
アクセスメソッド
Rubyではオブジェクトの外部からインスタンス変数を直接参照したり、値を代入したりすることはできません。そのためオブジェクトの内部の情報にアクセスするメソッドを定義する必要がありますが、それをアクセスメソッドと言います。Javaでいうgetterとsetterのような感じです。
class Foo @name def name @name end def name=(value) # 呼び出しは`~.name = "hogs"`でOK @name = value end end
しかし、上記のように全て定義するのは大変なので、以下のようにインスタンス変数を示すシンボルを指定すると、インスタンス変数も含めて自動で定義してくれます。
attr_reader :name
参照のみ可能にする(nameメソッドを定義する)attr_writer :name
変更のみ可能にする(name=メソッドを定義する)attr_accessor :name
参照と変更の両方を可能にする(上記2つを定義する)
要はこのメソッドを使うと、上記の例がそのまま展開されるようなイメージです。また、定数にアクセスメソッドは使えません。
self変数について
インスタンスメソッドの中でメソッドのレシーバ自身を参照するには self という変数を使います。
def name @name end def hello puts "Hi, I am #{self.name}." end
この場合は helloメソッドを呼び出した時のレシーバを参照することになります。また、レシーバを省略してメソッドを呼ぶと暗黙的に self をレシーバとするため、省略して#{name}としても nameメソッドが呼ばれることに変わりはありません。
ただし、この場合でも アクセスメソッドの setter を使いたい時にname = "hoge"
と書いてしまうと、nameというローカル変数が作成されてしまうため、self.name = "hoge"
としてレシーバを明示する必要があります。
クラスメソッド
インスタンスではなくてクラスそのものをレシーバとするメソッドで、Java でいう staticメソッドみたいなものです。インスタンスに対する操作ではなく、そのクラスに関連する操作のために使われます。
class << HelloWorld def hello(name) # クラスメソッド ... end def hoge # クラスメソッド ... end end HelloWorld.hello("task") HelloWorld.hoge
class HelloWorld class << self def hello(name) # クラスメソッド ... end end def hoge # インスタンスメソッド ... end end HelloWorld.hello("task") test = HelloWorld.new test.hoge
class HelloWorld def HelloWorld.hello(name) # クラスメソッド ... end def self.hoge # クラスメソッド(クラス定義内なので self 使用) ... end end def HelloWorld.fuga # クラスメソッド
メソッドの呼び出しを制限する
メソッドには3種類の呼び出し制限があります。
public
メソッドをインスタンスメソッドとして制限なしに使えるようにします。
private
メソッドをレシーバを指定して呼び出せないようにします。レシーバを省略した形式(関数形式)でしか呼べないのでインスタンスの外側から使えません。
protected
メソッドを同一のクラスであればインスタンスメソッドとして使えます。メソッドを外側から呼べないのは private と同じですが、レシーバに self のみ指定することができます。
メソッドの呼び出し制限を変更するには次のようにします。
class HelloWorld def hoge ... end public :hoge def fuga ... end protected :fuga
この他に、private とのみ記述して、それ以降に定義されるメソッドをまとめて private にすることもできます。また、何も指定せずに定義されたメソッドは public になりますが、initializeメソッドだけは private として定義されます。
クラスの継承について
すでに定義されているクラスを拡張して新しいクラスを作ることを継承といいます。継承によって新しく作られたクラスを「サブクラス」、もとになったクラスを「スーパークラス」といいます。
Rubyのすべてのクラスは BasicObject クラスのサブクラスですが、BasicObject は本当に最低限の機能であるため、通常のオブジェクトに必要なクラスは Object クラスとして定義されており、基本的にほぼすべてのクラスの親は Object と考えていいです。Object クラスは BasicObject クラスを継承し、Kernel モジュールをインクルードしています。
サブクラスとスーパークラスの関係を調べるには、.is_a?(klass)
メソッドか、.kind_of?(klass)
メソッドを使います。
ary = Array.new() p ary.is_a?(Object) # ArrayクラスはObjectクラスのサブクラスのためtrue #=>true p ary.kind_of?(BasicObject) # ArrayクラスはBasicObjectクラスのサブクラスのためtrue #=>true p ary.instance_of?(Object) # Objectクラスのインスタンスではないためfalse #=>false
instance_of?(klass)
メソッドの場合はあるクラスのインスタンスかどうかしか判断できませんが、is_a?(klass
と.kind_of?(klass)
は継承関係をさかのぼって判断してくれます。
クラスを継承する
クラスを継承するには次のように記述します。
class クラス名 < スーパークラス名 クラスの定義 end
メソッドにはスーパークラスの同名メソッドを再定義することもできます。元のメソッドを呼び出したい時は super を使います。
class MyString < String def eql?(str) # eql?()メソッドの再定義 ... super(str) # スーパークラスのeql?メソッドを呼ぶ end end
継承ではないですが既存のクラスにメソッドを追加することもできます。
class String def hoge ... end end "test".hoge