はじめに
いきなりですが、Rubyでクラスメソッドを定義する際に、class << self
と記述したことはありますか?
おそらく、Rubyを使ったことのある人であれば、一度は記述したことがあると思います。
このclass << self
について、僕の中では
- クラスメソッドを定義するときの構文である
- この中に書けばいちいち
self
を書く必要がない
というぐらいの浅い知識でしかなかったのですが、詳しく調べてみるとclass << self
でなぜクラスメソッドが定義できるのか知見が得られたため、この記事にまとめようと思います。
この記事の構成
この記事では以下の2点をまとめることで、表題について理解していこうと思います。
- Rubyのクラスメソッドがどのように定義されるのか
-
class << self
とは何なのか
この記事の対象者
この記事の対象者は以下の通りです。
- Rubyのクラスメソッドがどのように定義されるのか詳しく知らない人
- 僕と同じように
class << self
はクラスメソッドを定義するときの構文というくらいの知識しかない人
それでは、頑張っていきましょう。
Rubyのクラスメソッドがどのように定義されるのか
いきなりclass << self
の説明を見ても、Rubyのクラスメソッドがどのように定義されるのかを知らないと説明が理解できないため、まずはクラスメソッドがどのように定義されるのかを説明します。
特異メソッドが分かればクラスメソッドが分かる
特異メソッド?
クラスメソッドと違うのでは?
何で特異メソッドについて知る必要があるの?
と思うかもしれませんが、特異メソッドを知ることが、クラスメソッドを知ることに繋がるため、まずは特異メソッドについて説明します。
特異メソッドって何?
そもそも特異メソッドとは何でしょうか?
端的に言うと、特定のオブジェクトだけが持つメソッドのことです。
特異メソッドを定義する
上の説明だけでは伝わりにくいと思いますので、実際に特異メソッドを定義するコードを見てみます。
name = 'tomoprog'
# 特異メソッドを定義する
def name.strong
"** #{self} **"
end
puts name
puts name.strong
tomoprog
** tomoprog **
今回ではname
が特定のオブジェクトにあたります。
つまり、ここで定義したstrong
というメソッドはname
だけが持つメソッドとして定義されます。
name
以外のオブジェクトでstrong
メソッドを実行した場合にどうなるか見てみましょう。
name = 'tomoprog'
another = 'another' # name以外のオブジェクト
# 特異メソッドを定義する
def name.strong
"** #{self} **"
end
puts name
puts name.strong
puts another.strong # これは実行できる?
undefined method `strong' for "another":String (NoMethodError)
NoMethodError
となり、name
以外のオブジェクトではstrong
メソッドが存在しないことが分かると思います。
特異メソッドはどこに定義されるのか
特異メソッドを定義することで、特定のオブジェクトにだけメソッドを定義できることは分かりました。
それでは、この特異メソッドがどこに定義されるのか、もう少し詳しく見てみましょう。
特異メソッドを定義するとそのメソッドはメソッドを定義したオブジェクトの特異クラスというクラスに定義されます。
先程の例をもとに図で説明すると、下のようになります。
ちなみに、特異クラスは特異メソッドを定義したときに自動で生成されるため、another
オブジェクトの特異クラスはまだ生成されていません。
それでは、実際に特異クラスにメソッドが定義されているのかを確認してみましょう。
特異クラスを参照するにはObject#singleton_class
を使用します。
name = 'tomoprog'
# 特異メソッドを定義する
def name.strong
"** #{self} **"
end
puts name.singleton_class # これで特異クラスを参照できる
puts name.singleton_class.method_defined? :strong
#<Class:#<String:0x0000000001a24490>>
true
この結果から特異クラスにstrong
メソッドが定義されていることが分かると思います。
クラスに特異メソッドを定義する
特異メソッドの定義方法が分かったところで、今度はクラスに特異メソッドを定義してみましょう。
class NamePrinter; end
def NamePrinter.strong(name)
"** #{name} **"
end
puts NamePrinter.strong('tomoprog')
** tomoprog **
ここで、strong
メソッドの呼び出し方をよく見てください。
クラスメソッドの呼び出し方と全く同じであることが分かると思います。
つまり、クラスメソッドの正体はクラスの特異メソッドであるということです。1
これをクラス定義式の中に書くと、
class NamePrinter
def NamePrinter.strong(name)
"** #{name} **"
end
end
さらにNamePrinter
をself
に変えれば、
class NamePrinter
def self.strong(name)
"** #{name} **"
end
end
よく見るクラスメソッドの定義方法と同じになることが分かると思います。
class << self
とは何なのか
ここまでの説明で、クラスメソッドが特異メソッドであるということは理解いただけたでしょうか?
クラスメソッドが特異メソッドであることが分かるとclass << self
の説明も理解できるようになります。
このclass << self
という記述は特異クラス定義式と呼ばれ、指定したオブジェクトの特異クラスをクラス定義式と同じように記述できるものです。
指定したオブジェクトというのは<<
の右側に書いてあるオブジェクト、つまりclass << self
であれば、self
の特異クラスをクラス定義式と同じように記述できるということです。
つまり、class << self
はself
の特異クラスにメソッドを定義することで、特異メソッドを定義しているのです。
特異クラス定義式でメソッドを定義する
それでは、実際に特異クラス定義式でメソッドを定義してみましょう。
class NamePrinter; end
class << NamePrinter
def strong(name)
"** #{name} **"
end
end
puts NamePrinter.strong('tomoprog')
** tomoprog **
class << NamePrinter
でNamePrinter
の特異クラスに対してメソッドを定義することで、NamePrinter
の特異メソッドを定義しています。
これを先ほどと同じようにクラス定義式に入れてあげると
class NamePrinter
class << NamePrinter
def strong(name)
"** #{name} **"
end
end
end
さらにNamePrinter
をself
に変えれば、
class NamePrinter
class << self
def strong(name)
"** #{name} **"
end
end
end
見慣れたclass << self
になりました。
まとめ
- クラスメソッドとはクラスの特異メソッド(特異クラスに定義されたメソッド)である
-
class << self
はself
の特異クラスに対してメソッドを定義している
class << self
について調べることで、Rubyのクラスメソッドについての知見が今までよりも得られたと思います。
この記事がRubyを使ってなんとなくクラスメソッドを定義している人に少しでも役にたてば幸いです。
それではまた。
TomoProg
参考
-
もっと詳しく言うと、Classクラスのオブジェクトの特異メソッドと言えますが、Classクラスからのオブジェクトの生成を説明していないため、ここではクラスの特異メソッドという表現にしています。詳しく知りたい方はClassクラスからクラスを生成する方法を調べてみてください。 ↩