Ruby mixins:扩展和包含 [英] Ruby mixins: extend and include
问题描述
我一直在阅读一些关于Ruby的mixin方法的文章, extend
和 include
,我仍然不太确定这种行为。我知道 extend
会将给定模块的实例方法作为单例方法添加到执行扩展的模块,并且 include
本质上会将一个模块的内容(方法,常量,变量)附加到包含它的那个,有效地在接收器中定义它们。
I've been reading a few articles about Ruby's mixin methods, extend
and include
, and I am still not quite sure about the behavior. I understand that extend
will add the instance methods of the given module as singleton methods to the module doing the extending, and that include
will essentially append the contents of a module (methods, constants, variables) to the one doing the including, effectively defining them in the receiver.
然而,在一些之后修补,试图了解行为将如何表现,我有几个问题。这是我的测试设置:
However, after some tinkering, trying to get a feel for how the behavior will manifest, I've got a few questions. Here is my testing setup:
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
正如我所料,模块 Bar
获得 Baz
( #blorg
)中定义的实例方法,就好像它们一样d由于包含方法本身已定义,并且类培根
获得单例方法 Bacon :: blah
和 Bacon :: blorg
扩展名。
So as I would expect, module Bar
gains the instance methods defined in Baz
(#blorg
) as if they'd been defined in itself due to the inclusion method, and class Bacon
gains the singleton methods Bacon::blah
and Bacon::blorg
by extension.
Bacon.blah # => blah
Bacon.blorg # => blorg
并且类 Egg
获得定义的方法在 Bar
( #blah
,现在 #blorg
)as实例方法。
And class Egg
gains the methods defined in Bar
(#blah
and now #blorg
) as instance methods.
Egg.new.blah # => blah
Egg.new.blorg # => blorg
我得到了所有这些,所以这很好。
I get all that, so that's good.
但是,我不理解使用 #ancestors
和 #is_a?
的回复方法。
However, I don't understand the responses I get from using the #ancestors
and #is_a?
methods.
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
。为什么会这样?
It would seem that extending a module causes the #is_a?
method to return true
when queried about that module, but it is not added to the ancestors of the class, and vice versa with regards to inclusion: the ancestors of the class contains the modules being included, but the #is_a?
method returns false
when queried. Why does this happen?
推荐答案
区别在于 include
会添加包含类的祖先包含的类,而 extend
将扩展类添加到扩展类的单例类的祖先。唷。我们先来看看会发生什么:
The difference is that include
will add the included class to the ancestors of the including class, whereas extend
will add the extended class to the ancestors of the extending classes' singleton class. Phew. Let's first observe what happens:
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
class
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
。另一件事是,在创建实例时,类的所有祖先都成为实例的单例类的祖先。因此,对于所有新创建的任何类的实例,这将评估为true:
So what foo.is_a? Klass
actually does is to check whether foo.singleton_class.ancestors
contains Klass
. The other thing happening is that all the ancestors of a class become ancestors of an instances' singleton class when the instance is created. So this will evaluate to true for all newly created instances of any class:
Egg.ancestors == Egg.new.singleton_class.ancestors
那么这一切意味着什么呢? extend
和 include
在不同的级别上执行相同的操作,我希望下面的示例明确说明两种方式一个类基本上是等价的:
So what does all this mean? extend
and include
do the same thing on different levels, i hope the following example makes this clear as both ways to extend a class are essentially equivalent:
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
其中 class<< self
只是进入单例类的奇怪语法。所以 extend
实际上只是单例类中 include
的简写。
where class << self
is just the odd syntax to get to the singleton class. So extend
really just is a shorthand for include
in the singleton class.
这篇关于Ruby mixins:扩展和包含的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!