はじめに
Rubyのメタクラスについて本質的な解説をしている人がいなかったので自分なりに解説してみました。
※前提として特異メソッド/特異クラスを多少知っている人向けです
Classクラスについて
Rubyにおいて”クラス”はClassクラスのインスタンスであるというのは、ある程度Rubyをかじったことがある人ならば聞いたことがあると思われる。
その通り、RubyにはClassクラスがあり、それをインスタンス化してクラスを定義することが可能である。
以下の2つは同義である。
class Hoge; end
Hoge = Class.new
メタクラスとは
一方で、Classクラスの特異メソッドnewについてリファレンスを読んでみると以下のような記述がある。
新しく名前の付いていない superclass のサブクラスを生成します。
名前のないクラスは、最初に名前を求める際に代入されている定数名を検索し、見つかった定数名をクラス名とします。
「名前の付いていない superclass のサブクラスを生成します」
そう、Class.newによって生成されるオブジェクト自体は無名のクラスなのである。
a = Class.new
p a.name #=> nil
実はこれがメタクラスに該当する。
メタクラスは名前を持たないため、クラスでありながら定数ではなく変数に保持される。
また、メタクラスは定数に代入すると、定数名をクラス名としてメタクラスを参照することが可能である。
a = Class.new
Hoge = a
p a.name #=> "Hoge"
p Hoge.name #=> "Hoge"
つまりHogeクラスはClassクラスから直接生成されるオブジェクトではなく、あくまでメタクラスを参照しているだけである。
メタクラスとクラスメソッド
メタクラスに特異メソッドを定義すると、Hogeクラスの静的メソッドのように振る舞わせることができる。
a = Class.new
Hoge = a
def a.hello
puts "hello"
end
a.hello #=> "hello"
Hoge.hello #=> "hello"
hoge = Hoge.new
hoge.hello #=> NoMethodError
ちなみにこれがRubyのクラスメソッドと呼ばれる物の正体である。
クラスメソッドの定義方法として使われる特異クラスを開く方法は、つまるところメタクラスにメソッドを追加しているわけである。
class Hoge
class << self #Hogeクラス自身の特異クラスを開く
def hello
puts "hello"
end
end
end
Hoge.hello #=> "hello"
最後に
メタクラスはユーザーに意識させたくないクラスらしく、ぶっちゃけリファレンスによるとたいして重要なことでもないみたいです。
ただ、メタクラスがよくわからずモヤモヤしている人や本質的な部分の理解を深めたい人の一助となっていただければ幸いです。