【Ruby】Mix-inの挙動

ABOUTこの記事をかいた人

気になること&知らないことをひたすらググることを得意としています。最近は「Ruby」というプログラム言語が特に気になってきました。このブログでは最近気になったことを中心に記事を書いていきます。記事には間違った情報を書かないように細心の注意を払っていますが、もし誤りがあった場合はコメントやお問い合わせフォームからご指摘いただければ幸いです。

「Mix-in(ミックスイン)」を行うことで、インクルードしたクラスの上の階層に動作を定義できますので結果的に仮想的なスーパークラスとして作用してくれます。まずは↓のスクリプトをみていきましょう。

今回は「Class1」にモジュール「Mix」をインクルードして、「Class2」にはインクルードしていません。インクルードされているかどうかを調べるには「include?」メソッドを使います。

記述方法は「調べるクラス名.include?(モジュール名)」で調べるとブーリアン値が返ってきます。

true
false

インクルード時の継承関係

インクルードされたクラスとされていないクラスの継承関係の違いを見ていきましょう。

[Class1, Mix, Object, Kernel, BasicObject]
Object
[Class2, Object, Kernel, BasicObject]
Object

「ancestors」メソッドを使うと継承関係にある全てのクラスの表示ができます。処理を実行する場合この表示の中で左から順番にメソッドを検索して最初に見つかったものを実行するようになっています。

実行結果の1行目をみてみると「Class1」と「Object」の間に「Mix」が入っていて「Mix」から「Class1」に継承できていることがわかります。

継承関係としては↓のような感じになることがわかります。
BasicObject→Kernel→Object→Mix→Class1

ちなみに「Object」クラスは全てのクラスのスーパークラスとなり、「Kernel」モジュールをインクルードしているので継承関係は「Kernel→Object」となります。

「BasicObject」クラス「Ruby1.9」以降に登場しているようで、「Object」クラスのスーパークラスとなっています。
参考:BasicObject

「superclass」メソッドを実行するスーパークラスが返ってきます。今回の場合スーパークラスは「Object」であることがわかります。

クラスを継承した場合

蛇足かとは思いますが、定義したクラスを継承し、念のためインクルードした場合についてもみていきます。

true
true
[Class2, Mix2, Class1, Mix, Object, Kernel, BasicObject]
Class1

「Class1」を「Class2」に継承したので実行結果の1、2がちゃんと「true」で返ってきていて、モジュール「Mix」「Mix2」がインクルードされていることがわかります。

継承関係でもClass1→Mix2→Class2となって、Class1がClass2に継承されて更に、インクルードしたMix2モジュールもそこに挟み込まれるように継承が行われています。これでClass1の機能を継承しつつ、「Mix2」モジュールからも機能を追加することができるようになります。

メソッド実行時の検索順

メソッド名が同一の場合

クラスとMix-inしたモジュールで両方とも同じ名前があった場合は、検索順で早いクラスの方が実行されます。今回は両方とも「mix_in」という同名のメソッドがありますが、検索順で早い「Class1」のメソッドが実行されることになります。

[Class1, Mix, Object, Kernel, BasicObject]
class→Class1

複数インクルードした場合

複数のモジュールがクラス内にインクルードされている場合は、後からインクルードしたメソッドから実行されます。今回は「Mix2」のインクルードが後になっているので「Mix2」モジュールから検索が行われてメソッドが実行されています。

[Class1, Mix2, Mix1, Object, Kernel, BasicObject]
Mix2!!

インクルードが入れ子の場合

入れ子の状態でMix-inしている場合は、下記のようになります。「Class1」にモジュール「Mix2」がインクルードされているのでまずはそこから検索が行われ、モジュール「Mix2」にインクルードしている「Mix1」モジュールが検索されることになります。

[Class1, Mix2, Mix1, Object, Kernel, BasicObject]
Mix2

同じモジュールを複数回インクルードした場合

複数回インクルードした場合では、2回目以降はスルーされます。

[Class1, Mix2, Mix1, Object, Kernel, BasicObject]
Mix2

この場合で後から「Mix1」を再度入力しても検索順では「Mix2」モジュールが優先されるので、「Mix1」を優先させたい場合は初めの「Mix1」のインクルードを削除する必要があります。

extendメソッド

extendメソッドを使うと、特異クラスにモジュールをインクルードしてくれます。こうすることによってメソッドを特定のオブジェクトで使えるようになります。また、普通に特異クラスにてモジュールをインクルードしても同様に機能の追加ができます。

extendメソッドでクラスメソッドを追加

先程の場合はオブジェクトにextendメソッドを使い、モジュールをインクルードしましたが、下記の17、18行目のようにクラスオブジェクトにextendメソッドを使うとクラスメソッドを追加することができます。

【整理】クラス内でextendまたはincludeした場合

「ClassMethod」モジュールをextendし、「InstanceMethod」モジュールをincludeした場合をみていきましょう。

c
i

上記の場合をみてみるとextendするとクラスメソッドが追加され、includeするとインクルードメソッドが追加されていることがわかります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ABOUTこの記事をかいた人

気になること&知らないことをひたすらググることを得意としています。最近は「Ruby」というプログラム言語が特に気になってきました。このブログでは最近気になったことを中心に記事を書いていきます。記事には間違った情報を書かないように細心の注意を払っていますが、もし誤りがあった場合はコメントやお問い合わせフォームからご指摘いただければ幸いです。