从多个模块继承?

时间:2016-11-29 08:16:57

标签: ruby inheritance module

我理解当一个模块包含在一个类中时,它的行为就像它所包含的类的直接超类。

但是,如果同一个班级中包含多个模块怎么办?如果模块之间没有关系,哪一个现在是直接超类?

如果模块A包含模块B(因此在某种程度上存在关系),会覆盖它的一些方法,现在A和B都包含在同一个类中。该类现在是否定义了A和B中的所有方法,以及A和B共有的方法,它只使用A覆盖的方法吗?

2 个答案:

答案 0 :(得分:3)

为了帮助您了解这一点,ruby为您提供了Module#ancestors

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

这是将搜索Object的实例方法的顺序。所以让我们测试你的例子。

首先,包括两个模块:

module M; end
module N; end
class C
  include M
  include N
end

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

因此首先在C中搜索方法。如果找不到具有给定名称的方法,则首先在N中搜索,然后在M中搜索。换句话说 - 您包含模块的相反顺序。

其次,模块,包括一个模块,包含在一个类中:

module X; end
module Y
  include X
end
class K
  include Y
end

K.ancestors # => [K, Y, X, Object, Kernel, BasicObject]

因此,我们可以看到相同的规则适用于包含在模块中。正如在前面的示例中一样,首先在C中搜索一个方法,然后只在C中包含的模块中搜索一个方法,这里首先将在一个模块中搜索一个方法,然后才在该模块中包含的模块。

除了一致性之外,其原因是类实际上是Ruby中的模块:

Class.superclass # => Module

有很多规则。例如,在层次结构中包括两次相同的模块,单例类,#prepend#method_missing等等。但是你可以推断所有这些知道如何使用#ancestors

答案 1 :(得分:1)

  

我理解当一个模块包含在一个类中时,它的行为就像它所包含的类的直接超类。

它不像“直接超类”那样“行为”。 成为直接超类(以及之前的直接超类,成为模块的直接超类)。

  

但是,如果同一个班级中包含多个模块怎么办?如果模块之间没有关系,哪一个现在是直接超类?

没有区别。当你包含一个模块时,会创建该模块的include类,并且包含类成为模块所包含的类的直接超类,而之前的直接超类,现在成为include类的直接超类。你可以随意重复这个。

  

如果模块A包含模块B(因此在某种程度上存在关系),

我掩盖了这个细节,但它也很简单:上面概述的过程递归地应用于模块中包含的模块。因此,如果模块A包含B,而课程C包含A,那么

  1. 创建包含类A′
  2. C的直接超类(大概是Object,但可能是任何东西)变成A′的超类
  3. A′成为C的超类
  4. 该过程以递归方式应用于A中包含的模块和A中包含的模块中包含的模块等等......:
    1. 创建包含类B′
    2. A′的直接超类成为B′的超类
    3. B′成为A′的超类
    4. 该过程以递归方式应用于B中包含的模块以及B中包含的模块中包含的模块等等......
  5.   

    覆盖了它的一些方法,现在A和B都包含在同一个类中。

    您不能同时包含AB。 Ruby将检查模块是否已经在祖先链中,并且只包含一次。由于包含A已包含B,因此您无法再次添加B

      

    该类现在是否定义了A和B中的所有方法,以及A和B共有的方法,它只使用A覆盖的方法?

    该类没有定义任何方法。从模块继承并不会神奇地定义任何方法。它只是使模块成为超类,就是它。

    请不要让Class#superclass的返回值混淆你:它返回类的超类指针,而是返回最近的非超类的超类类。