16

extendRuby の mixin メソッド、およびに関する記事をいくつか読んでいますがinclude、その動作についてはまだよくわかりません。extend特定のモジュールのインスタンス メソッドをシングルトン メソッドとして拡張を行うモジュールにinclude追加し、モジュールの内容 (メソッド、定数、変数) をインクルードを行うモジュールに本質的に追加し、それらを効果的に定義することを理解しています受信機。

しかし、動作がどのように現れるかを感じようと試行錯誤した後、いくつか質問があります。これが私のテスト設定です:

module Baz
  def blorg
    puts 'blorg'
  end
end

module Bar
  include Baz
  def blah
    puts 'blah'
  end
end

module Foo
  extend Bar
end

class Bacon
  extend Bar
end

class Egg
  include Bar
end

予想通り、moduleは( )Barで定義されたインスタンス メソッドを包含メソッドによってそれ自体で定義されているかのように取得し、class はシングルトン メソッドと拡張によって取得します。Baz#blorgBaconBacon::blahBacon::blorg

Bacon.blah  # => blah
Bacon.blorg # => blorg

また、クラスは( and now )Eggで定義されたメソッドをインスタンス メソッドとして取得します。Bar#blah#blorg

Egg.new.blah  # => blah
Egg.new.blorg # => blorg

私はそれをすべて理解していますので、それは良いことです。

#ancestorsただし、および#is_a?メソッドを使用して得られる応答がわかりません。

Bacon.ancestors  # => [Bacon, Object, Kernel, BasicObject]
Bacon.is_a? Bar  # => true

Egg.ancestors    # => [Egg, Bar, Baz, Object, Kernel, BasicObject]
Egg.is_a? Bar    # => false

モジュールを拡張すると、そのモジュールについて照会されたときに#is_a?メソッドが返されるように見えtrueますが、それはクラスの祖先に追加されず、包含に関してはその逆です: クラスの祖先には含まれるモジュールが含まれていますが、#is_a?メソッドはfalse照会されると戻ります。なぜこれが起こるのですか?

4

2 に答える 2

28

違いはinclude、インクルード クラスをインクルード クラスの祖先に追加するのに対しextend、拡張クラスを拡張クラスのシングルトン クラスの祖先に追加することです。ふぅ。まず何が起こるか観察しましょう:

Bacon.ancestors
#=> [Bacon, Object, Kernel, BasicObject]

Bacon.singleton_class.ancestors
#=> [Bar, Baz, Class, Module, Object, Kernel, BasicObject]

Bacon.new.singleton_class.ancestors
#=> [Bacon, Object, Kernel, BasicObject]

Bacon.is_a? Bar
#=> true

Bacon.new.is_a? Bar
#=> false

そして、Eggクラスのために

Egg.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]

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

Egg.new.singleton_class.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]

Egg.is_a? Bar
#=> false

Egg.new.is_a? Bar
#=> true

したがって、foo.is_a? Klass実際に行うことは、がfoo.singleton_class.ancestors含まれているかどうかを確認することKlassです。もう 1 つのことは、インスタンスが作成されると、クラスのすべての祖先がインスタンスのシングルトン クラスの祖先になることです。したがって、これは、任意のクラスの新しく作成されたすべてのインスタンスに対して true と評価されます。

Egg.ancestors == Egg.new.singleton_class.ancestors

では、これはどういう意味ですか?extendクラスをinclude拡張する両方の方法は本質的に同等であるため、次の例でこれが明確になることを願っています。

module A
  def foobar
    puts 'foobar'
  end
end

class B
  extend A
end

class C
  class << self
    include A
  end
end

B.singleton_class.ancestors == C.singleton_class.ancestors
#=> true

whereclass << selfシングルトンクラスに到達するための奇妙な構文です。したがって、シングルトン クラスでextendは、「just」は省略形です。include

于 2013-07-09T16:48:12.097 に答える
0
Egg.is_a? Egg # => false

インクルードは、Eggクラスのインスタンスを (効果的に) 変更します。まったく同じではありませんが、次のようなことを行うのと非常に似ています

class Egg < Bar
end

拡張がクラスメソッドを追加するとき、これは次のようなことをするのと非常に似ています

class Bacon
  class << self
    include Bar
  end
end

クラスのインスタンスの変更を含めるように考えることができますが、extend は実際にクラスを変更します。

于 2013-07-09T16:14:21.617 に答える