Ruby mixins:扩展和包含 [英] Ruby mixins: extend and include

查看:109
本文介绍了Ruby mixins:扩展和包含的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读一些关于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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆