インスタンスのクラスのextendメソッドが継承とは異なる動作をするのはなぜですか?

Artur Martsinkovskyi
module B
  def a
    print 'B'
    super
  end
end

class A
  extend B

  def a
    print "A"
  end

  def self.a
    print "A"
  end
end

a = A.new

a.extend B
puts a.a # => BA
puts A.a # => A

Kernel#extendメソッドがクラスオブジェクトとクラスインスタンスオブジェクトで異なる動作をするのはなぜですか?インスタンスを拡張すると、継承のチェーンの前にモジュールが追加されるように見えますが、代わりにクラスを拡張すると、モジュールがクラスの上に配置されます。

fphilipe

まず、いくつかの概念を紹介します。

まず、を使用してクラスメソッドをdef self.a定義することは、クラスのシングルトンクラスでメソッドを定義することと同じです。

class C
  def self.a; end

  class << self
    def b; end
  end
end

C.method(:a) # => #<Method: C.a>
C.method(:b) # => #<Method: C.b>

さらに、オブジェクトのメソッドは、そのオブジェクトのシングルトンクラスのインスタンスメソッドです。

C.singleton_class.instance_method(:a) # => #<UnboundMethod: #<Class:C>#a>
C.singleton_class.instance_method(:b) # => #<UnboundMethod: #<Class:C>#b>

#b上記で定義した方法を見るとselfプレフィックスが付いていないことがわかります。したがって、これは単なるインスタンスメソッドです。

次に、シングルトンクラス#extendと同じ#includeです。

module M; end

class C1
  extend M
end

class C2
  class << self
    include M
  end
end

C1.ancestors # => [#<Class:C2>, M, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
C2.ancestors # => [#<Class:C1>, M, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

通知はどのようにM今の祖先の一部であるC1C2同じようインチ

含める(または拡張する)Mことも、次のように達成できます。

C1.extend M
C2.singleton_class.include M

最後に、#includeモジュールを作成すると祖先がどうなるかに注意してください

module M1; end
module M2; end
class C; end

C.include M1
C.ancestors # => [C, M1, Object, Kernel, BasicObject]

C.include M2
C.ancestors # => [C, M2, M1, Object, Kernel, BasicObject]

すべては、#include(受信した後に挿入されたモジュールが得られC先祖連鎖この場合)。

それでは、あなたの定義を見てみましょう(本文を省略します):

module B; end

class A
  extend B
end

覚えておいてください、#extendと同じである#include#singleton_classしたがって、次のように書き直すことができます。

module B; end
class A; end
A.singleton_class.include B

シングルトンクラスの祖先は、B最初の項目の後にあります。これは、Aクラスメソッドが定義されているシングルトンクラスです(したがって、クラスメソッドは、問題のクラスのシングルトンクラスのインスタンスメソッドにすぎないことに注意してください)。

A.singleton_class.ancestors # => [#<Class:A>, B, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

コードの2番目の部分に移ります。

a = A.new
a.extend B

を使用して書き直します#include

a = A.new
a.singleton_class.include B

祖先を確認しましょう:

a.singleton_class.ancestors # => [#<Class:#<A:0x00007f83e714be88>>, B, A, Object, Kernel, BasicObject]

この場合も#include、モジュールを祖先チェーンの最初の要素の後に配置し、結果として。のB前に配置しましたA

これは、(つまりに送信#aするとき、に応答する最初の祖先を探すことを意味します。この場合はそうです。次に、を呼び出しますこれは、に応答する祖先チェーンに沿って続行さます。aa.a#aBBsuperA#a

さてA.a、それは異なります。Aのシングルトンクラスの祖先を思い出してください

A.singleton_class.ancestors # => [#<Class:A>, B, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

B後に来ることに注意してください#<Class:A>のクラスメソッドである、に#<Class:A>すでに応答していますそのメソッドはを呼び出さないためは呼び出されません。したがって、同じ出力は得られません。#aAsuperB#a

あなたが持っているしたい場合はB前に#<Class:A>、あなたはプリペンドBにする必要があると思いますAのシングルトンクラス。最初のアイテムの後に#prependオブジェクトを挿入する、とは異なり#include祖先チェーンの最初にオブジェクトを挿入します(これを機能させるにextend Bは、コード内のを削除する必要があります。そうしないBと、すでに祖先である場合何も起こりません)。

A.singleton_class.prepend B
A.singleton_class.ancestors # => [B, #<Class:A>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

呼び出すA.aと、と同じa.a、つまりprintが生成されますBA

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

@propertyメソッドを使用すると、hasattrがクラスとインスタンスで異なる動作をするのはなぜですか?

分類Dev

Pythonでネストされた辞書を設定する:クラスメソッドがスタンドアロン関数とは異なる動作をするのはなぜですか?

分類Dev

numpy配列から継承するクラスのメソッドが異なるものを返すのはなぜですか?

分類Dev

'this'と 'prototype'がコンストラクターとインスタンスで異なる動作をするのはなぜですか?

分類Dev

hasOwnPropertyがコンストラクター関数とインスタンスで異なる動作をするのはなぜですか?

分類Dev

クラスインスタンスメソッドのバインドがクラスメソッドのバインドと異なるのはなぜですか?

分類Dev

クロスメタ演算子を使用すると、** 2と²の動作が異なるのはなぜですか?

分類Dev

Pythonのインラインクラスメソッドがメタクラスで定義されたメソッドとは異なる動作をする理由

分類Dev

クラスメソッドをインスタンスごとに異なる動作にすることはできますか?

分類Dev

私のクラスがその基本クラスで定義されているメソッドを継承しないのはなぜですか?

分類Dev

なぜクラスの静的メソッドは継承されますが、インターフェースの静的メソッドは継承されないのですか?

分類Dev

__setメソッドと__getメソッドはクラスの内部と外部で異なる動作をすることができますか?

分類Dev

最終クラスは継承できないが、最終メソッドは継承できるのはなぜですか?

分類Dev

プライベートセッターが他のプライベートメソッドとは異なる動作をするのはなぜですか?

分類Dev

Python-インスタンスでクラスメソッドを呼び出すことができるのはなぜですか?

分類Dev

最初の関数が先行する場合、サブスクライブハンドラー関数の動作がonValueと異なるのはなぜですか?

分類Dev

インスタンスメソッドが静的コンテキストで使用されている場合、javacが「エラー:クラスのメソッドを特定のタイプに適用できない」と出力するのはなぜですか?

分類Dev

jQueryのon / offメソッドが外部スクリプトと異なる動作をするのはなぜですか

分類Dev

reduce()メソッドでインデックスが予期せず動作することがあるのはなぜですか?

分類Dev

toBinaryStringがIntegerクラスのインスタンスメソッドではないのはなぜですか?

分類Dev

かっことコンマを使用してnumpy配列のインデックスを作成すると動作が異なるのはなぜですか?

分類Dev

プレフィックスが「self」の場合、Rubyインスタンスメソッドの呼び出しの動作が異なるのはなぜですか?

分類Dev

クラスメソッドで使用すると、インスタンスプロパティが未定義になるのはなぜですか?

分類Dev

ConEmuでgvimを起動すると、コマンドラインからではなくタスクで動作するのはなぜですか?

分類Dev

ConEmuでgvimを起動すると、コマンドラインからではなくタスクで動作するのはなぜですか?

分類Dev

なぜ抽象クラスはインスタンスメソッドを持つことができるのですか?

分類Dev

Lambda式がKotlinクラスとJavaクラスで異なる動作をするのはなぜですか?

分類Dev

pyzmqサブスクライバーがasyncioと異なる動作をするのはなぜですか?

分類Dev

すべてのメソッドがクラスから継承しないのはなぜですか?

Related 関連記事

  1. 1

    @propertyメソッドを使用すると、hasattrがクラスとインスタンスで異なる動作をするのはなぜですか?

  2. 2

    Pythonでネストされた辞書を設定する:クラスメソッドがスタンドアロン関数とは異なる動作をするのはなぜですか?

  3. 3

    numpy配列から継承するクラスのメソッドが異なるものを返すのはなぜですか?

  4. 4

    'this'と 'prototype'がコンストラクターとインスタンスで異なる動作をするのはなぜですか?

  5. 5

    hasOwnPropertyがコンストラクター関数とインスタンスで異なる動作をするのはなぜですか?

  6. 6

    クラスインスタンスメソッドのバインドがクラスメソッドのバインドと異なるのはなぜですか?

  7. 7

    クロスメタ演算子を使用すると、** 2と²の動作が異なるのはなぜですか?

  8. 8

    Pythonのインラインクラスメソッドがメタクラスで定義されたメソッドとは異なる動作をする理由

  9. 9

    クラスメソッドをインスタンスごとに異なる動作にすることはできますか?

  10. 10

    私のクラスがその基本クラスで定義されているメソッドを継承しないのはなぜですか?

  11. 11

    なぜクラスの静的メソッドは継承されますが、インターフェースの静的メソッドは継承されないのですか?

  12. 12

    __setメソッドと__getメソッドはクラスの内部と外部で異なる動作をすることができますか?

  13. 13

    最終クラスは継承できないが、最終メソッドは継承できるのはなぜですか?

  14. 14

    プライベートセッターが他のプライベートメソッドとは異なる動作をするのはなぜですか?

  15. 15

    Python-インスタンスでクラスメソッドを呼び出すことができるのはなぜですか?

  16. 16

    最初の関数が先行する場合、サブスクライブハンドラー関数の動作がonValueと異なるのはなぜですか?

  17. 17

    インスタンスメソッドが静的コンテキストで使用されている場合、javacが「エラー:クラスのメソッドを特定のタイプに適用できない」と出力するのはなぜですか?

  18. 18

    jQueryのon / offメソッドが外部スクリプトと異なる動作をするのはなぜですか

  19. 19

    reduce()メソッドでインデックスが予期せず動作することがあるのはなぜですか?

  20. 20

    toBinaryStringがIntegerクラスのインスタンスメソッドではないのはなぜですか?

  21. 21

    かっことコンマを使用してnumpy配列のインデックスを作成すると動作が異なるのはなぜですか?

  22. 22

    プレフィックスが「self」の場合、Rubyインスタンスメソッドの呼び出しの動作が異なるのはなぜですか?

  23. 23

    クラスメソッドで使用すると、インスタンスプロパティが未定義になるのはなぜですか?

  24. 24

    ConEmuでgvimを起動すると、コマンドラインからではなくタスクで動作するのはなぜですか?

  25. 25

    ConEmuでgvimを起動すると、コマンドラインからではなくタスクで動作するのはなぜですか?

  26. 26

    なぜ抽象クラスはインスタンスメソッドを持つことができるのですか?

  27. 27

    Lambda式がKotlinクラスとJavaクラスで異なる動作をするのはなぜですか?

  28. 28

    pyzmqサブスクライバーがasyncioと異なる動作をするのはなぜですか?

  29. 29

    すべてのメソッドがクラスから継承しないのはなぜですか?

ホットタグ

アーカイブ