15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Ruby】class << selfでなぜクラスメソッドが定義できるのか

Last updated at Posted at 2020-05-01

はじめに

いきなりですが、Rubyでクラスメソッドを定義する際に、class << selfと記述したことはありますか?
おそらく、Rubyを使ったことのある人であれば、一度は記述したことがあると思います。

このclass << selfについて、僕の中では

  • クラスメソッドを定義するときの構文である
  • この中に書けばいちいちselfを書く必要がない

というぐらいの浅い知識でしかなかったのですが、詳しく調べてみるとclass << selfでなぜクラスメソッドが定義できるのか知見が得られたため、この記事にまとめようと思います。

この記事の構成

この記事では以下の2点をまとめることで、表題について理解していこうと思います。

  1. Rubyのクラスメソッドがどのように定義されるのか
  2. 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メソッドが存在しないことが分かると思います。

特異メソッドはどこに定義されるのか

特異メソッドを定義することで、特定のオブジェクトにだけメソッドを定義できることは分かりました。
それでは、この特異メソッドがどこに定義されるのか、もう少し詳しく見てみましょう。

特異メソッドを定義するとそのメソッドはメソッドを定義したオブジェクトの特異クラスというクラスに定義されます。

先程の例をもとに図で説明すると、下のようになります。

スクリーンショット 2020-05-01 11.11.03.png

ちなみに、特異クラスは特異メソッドを定義したときに自動で生成されるため、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

さらにNamePrinterselfに変えれば、

class NamePrinter
  def self.strong(name)
    "** #{name} **"
  end
end

よく見るクラスメソッドの定義方法と同じになることが分かると思います。

class << selfとは何なのか

ここまでの説明で、クラスメソッドが特異メソッドであるということは理解いただけたでしょうか?

クラスメソッドが特異メソッドであることが分かるとclass << selfの説明も理解できるようになります。

このclass << selfという記述は特異クラス定義式と呼ばれ、指定したオブジェクトの特異クラスをクラス定義式と同じように記述できるものです。

指定したオブジェクトというのは<<の右側に書いてあるオブジェクト、つまりclass << selfであれば、selfの特異クラスをクラス定義式と同じように記述できるということです。

つまり、class << selfselfの特異クラスにメソッドを定義することで、特異メソッドを定義しているのです。

特異クラス定義式でメソッドを定義する

それでは、実際に特異クラス定義式でメソッドを定義してみましょう。

class NamePrinter; end
class << NamePrinter
  def strong(name)
    "** #{name} **"
  end
end

puts NamePrinter.strong('tomoprog')
実行結果
** tomoprog **

class << NamePrinterNamePrinterの特異クラスに対してメソッドを定義することで、NamePrinterの特異メソッドを定義しています。

これを先ほどと同じようにクラス定義式に入れてあげると

class NamePrinter
  class << NamePrinter
    def strong(name)
      "** #{name} **"
    end
  end
end

さらにNamePrinterselfに変えれば、

class NamePrinter
  class << self
    def strong(name)
      "** #{name} **"
    end
  end
end

見慣れたclass << selfになりました。

まとめ

  • クラスメソッドとはクラスの特異メソッド(特異クラスに定義されたメソッド)である
  • class << selfselfの特異クラスに対してメソッドを定義している

class << selfについて調べることで、Rubyのクラスメソッドについての知見が今までよりも得られたと思います。

この記事がRubyを使ってなんとなくクラスメソッドを定義している人に少しでも役にたてば幸いです。

それではまた。
TomoProg

参考

  1. もっと詳しく言うと、Classクラスのオブジェクトの特異メソッドと言えますが、Classクラスからのオブジェクトの生成を説明していないため、ここではクラスの特異メソッドという表現にしています。詳しく知りたい方はClassクラスからクラスを生成する方法を調べてみてください。

15
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?