Ruby の特異メソッド・特異クラスとはなんなのか?
まずは特異メソッドから。
Rubyでは、クラスではなくオブジェクトに固有のメソッドを定義できる仕組みがある。これを特異メソッドと呼ぶ。
例を見てみよう。
code:rb
hoge = 'hoge'
def hoge.say
puts 'hogehoge'
end
こんな感じで、特定のオブジェクトだけにメソッドを定義できる。このとき、Rubyは特定のオブジェクト固有のクラス(特異クラス)を作成して継承チェーンに組み込まれている。
大元となるStringクラスが拡張されたわけではない。他の文字列オブジェクトにsayメソッドを実行しても NoMethodError が出る。
code:rb
'bar'.say #=> undefined method `say' for "bar":String (NoMethodError) def object.method_nameのように特異メソッドを定義することを「特異メソッド形式」と呼ぶことがある。また、特異メソッドは singleton method とも呼ばれる。
シングルトンとは、オブジェクト指向プログラミングにおけるクラスのデザインパターンの一つで、実行時にそのクラスのインスタンスが必ず単一になるよう設計すること。
特異メソッド形式以外に、sayメソッドは以下のようにも定義できる。
code:rb
hoge = 'hoge'
class << hoge
def say
puts 'hogehoge'
end
end
class << hoge と宣言することで、クラスのインスタンスメソッドを定義するように、sayというメソッドを定義できているのがわかる。
このような定義方法を、「特異メソッド形式」に対して「特異クラス形式」と呼ぶ。hogeオブジェクト固有のクラス、つまり特異クラスを定義して、そのなかでメソッドを定義している。
ここで「あれ?クラスメソッドの定義方法と似てない?」と気づいた方がいるかもしれない。
そのとおりで、Rubyのクラスメソッドは実質的に特異メソッドである。(より正確には、クラスオブジェクトの特異メソッド)
code:rb
class Hoge
class << self
def say
puts 'saysay'
end
end
end
クラス内で使われる self は、Class クラスのインスタンスの Hoge class を指す。
code:rb
puts Hoge.new.class #=> Hogeクラス puts Hoge.new.class.class #=> Classクラス Rubyでは、クラスはClassクラスのインスタンスという仕組みになっている。Classクラスのオブジェクトが生成されて、Hogeというグローバル定数へ代入されている。
つまり、以下の2つは同義になる。
code:rb
class Hoge
class << self
def say
puts 'saysay'
end
end
end
#2 ↑は実際には以下の作業をしている。Hogeというグローバル定数に新たなClassクラスのオブジェクトを代入している Hoge = Class.new do
class << self
def say
puts 'saysay'
end
end
end
では、#2の形式で作ったHogeクラスに新たなメソッドを特異メソッド形式で追加してみると
code:rb
Hoge = Class.new do
class << self
def say
puts 'saysay'
end
end
end
def Hoge.yay
puts 'yayay'
end
Hogeクラスに新たなメソッドが追加され、クラスメソッドとして定義されているのがわかる。HogeもClassクラスのオブジェクトのひとつなので、Hoge.yayといった形で特異メソッドを定義できる。
よって、Rubyではクラスメソッドは実質的に特異メソッドだということがわかる。
特異クラスとは
code:rb
class << インスタンス
end
と特異メソッドを定義する部分。「特異クラス定義式」と呼ばれる。
この部分一体が特異クラスとなる。classクラスのインスタンスに対して特異クラスを定義している
code:rb
class Foo
def hi
puts 'hi'
end
end
Foo.instance_methods false
class << foo
def bye
puts 'bye'
end
end
foo.singleton_methods
foo.singleton_class.instance_methods false
参考資料