インクルードと拡張について掘り下げます



翻訳者のメモ:この投稿を読む前に、Rubyメタクラスを掘り下げた投稿にまず慣れることをお勧めします。



すべてのルービストは、 includeおよびextendの正式な定義に精通しています 。 モジュールインクルードを実行してクラスインスタンスメソッドを追加し、 拡張してクラスメソッドを追加します。 残念ながら、これらの定義は完全に正確ではありません。 インスタンスを使用する理由を説明できません メソッドをオブジェクトに追加するには、 (モジュール)拡張します。 この場合、 インスタンスを使用するべきではありません include (モジュール) ? この問題を理解するために、メソッドが保存されている場所を把握することから始めます。



私があなたのために保存するメソッドと私のメソッドを保存する人



Rubyのオブジェクトは独自のメソッドを保存しません。 代わりに、メソッドを保存するシングルトンクラスを作成します。



class A def self.who_am_i puts self end def speak_up(input) puts input.upcase end end
      
      





インタプリタはクラスAとそれに付随するシングルトンクラスを作成します(オブジェクトの名前の前にプレフィックス'を使用してオブジェクトのシングルトンクラスを参照します)。 クラスインスタンスメソッド( speak_upなど )は、クラスAに格納されているメソッドに追加されます クラスメソッド( who_am_iなど )はクラス'Aに格納されます



 A.singleton_methods #    'A #=> [:who_am_i]
      
      









クラスインスタンスでも同じことが起こります。 クラスAのオブジェクトがあり、それにメソッドを追加する場合、このメソッドをオブジェクト自体の中に保存することはできません。 Rubyのオブジェクトは独自のメソッドを保存しないことに注意してください。



 a = A.new def a.not_so_loud(input) puts input.downcase end
      
      





ここでも、オブジェクト「 a 」に対してnot_so_loudメソッドを格納するシングルトンクラスが作成されます。







これで、オブジェクト「 a 」にのみ属し、クラスAの他のオブジェクトに影響を与えないメソッドができました



私は父ですか?



クラスAには、オブジェクト「 a 」およびクラスAの他のすべてのオブジェクトに必要な継承チェーンに関するメソッドと情報が含まれています 同様に、シングルトンクラス'Aには、クラスAのメソッドと継承チェーン情報が含まれています クラスAをクラス'Aのオブジェクトと見なすことができます 秘trickは、 シングルトンクラスに直接アクセスできないことです。 これは、 A'Aにメソッドを追加することを何らかの形で区別する必要があることを意味します ここに含まれ拡張し 、遊びに来ます。



含む



モジュールをオブジェクトに含める場合、オブジェクトの継承チェーンにメソッドを追加します。



 class A include M end
      
      









これは、クラスAの祖先を確認することで簡単に確認できます



 A.ancestors #=> [A, M, Object, Kernel, BasicObject]
      
      







伸ばす



extendincludeと同じですが、オブジェクトのシングルトンクラス用です。



 class A extend M end
      
      









また、クラス'Aの先祖を確認することでこれを確認できます



 A.singleton_class.ancestors #=> [M, Class, Module, Object, Kernel, BasicObject]
      
      





オブジェクトにextendを使用することもできます。



 a = A.new a.extend(M) a.singleton_class.ancestors #=> [M, A, Object, Kernel, BasicObject]
      
      









拡張を単純にクラスメソッドを追加する方法と考える場合、これまでに行ったすべてのことはあまり意味がありません。 ただし、これをオブジェクトのシングルトンクラスにメソッドを追加する方法として見ると、上記の例がより明確になります。



フックが含まれています



include呼び出しは、 含まれるメソッドのプラグインをチェックします。 このメソッドは、includeを使用してモジュールが接続されたときに実行されます 。 接続の初期化コンストラクターのようなものです。 ご想像のとおり、 extendにはこれらの目的のための独自のメソッド-extendedがあります。 そのため、クラスメソッドとクラスインスタンスメソッドの両方を一度に追加する場合、これに含まれるフックを使用できます。



 module M def self.included(base) base.extend(ClassMethods) end def speak_up(input) puts input.upcase end module ClassMethods def who_am_i puts self end end end class C include M end c = C.new
      
      





まず、クラスCの継承チェーンにモジュールMを含めます







次に、 'Cクラスの継承チェーンにメソッドを追加して、 Cクラスを拡張します。







おわりに



includeおよびextendの一般的な使用よりも深く掘り始めると、奇妙で​​恐ろしいことがわかります。 ただし、基礎となる実装を理解することは価値があり、すべてがすぐに意味をなします。 インクルードを定義してもう一度拡張してみましょう。



include-モジュールメソッドをオブジェクトに追加します。

extend-オブジェクトのシングルトンクラスのinclude呼び出し。



インタープリターがどのように機能するかについてさらに詳しく知りたい場合は、Ruby Internalsに関するPatrick Farleyのプレゼンテーションをご覧になることをお勧めします。



翻訳者注: instance.include(Module)を使用できないもう1つの点は、 includeメソッドがModuleクラスのプライベートメソッドであることです。 一般に、この記事を読む前に、 extendincludeの作業も想像していなかったので、翻訳する価値があると考えました。



わかりやすく説明します。この記事でシングルトンクラスと呼ばれるものには、メタクラスと固有クラスという別の名前があります。 これは、Rubyコミュニティに「公式」名がまだない、まったく同じエンティティです。 私はシングルトンクラスを使用しました 元に近いです。 ただし、Matz(言語の作成者)は、用語eigenclassにより感銘を受けています。



All Articles