【问题标题】:inheritance from multiple modules?从多个模块继承?
【发布时间】:2017-04-13 03:37:31
【问题描述】:

我知道当一个模块被包含到一个类中时,它的行为就像它所包含的类的直接超类。

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

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

【问题讨论】:

标签: ruby inheritance module


【解决方案1】:

我知道当一个模块被包含到一个类中时,它的行为就像它所包含的类的直接超类。

它不会“表现得像”直接的超类。它成为直接超类(之前的直接超类成为模块的直接超类)。

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

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

如果模块 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中包含的模块中包含的模块等等......

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

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

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

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

请不要让Class#superclass 的返回值混淆您:它确实返回类的超类指针,而是返回最接近的不是包含类的超类。

【讨论】:

    【解决方案2】:

    为了帮助您理解这一点,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就可以推导出来。

    【讨论】:

    • 哦,还有更多。如果 C 类除了包括 2 个模块之外,还扩展了其他一些 Z 类怎么办?现在的优先级是:C、N、M、Z?
    • 所以当我从 C 中引用 super 时,我指的是 N 而不是 Z,对吧?
    • What if class C other than including 2 modules, also extends some other class Z - 类不能扩展。
    • @zwiebl, super 只是在祖先链上更进一步,试图找到一个同名的方法。如果“扩展”是指“继承自”,那么链将是 - 首先是 C,然后是包含的模块,然后是继承自的类。
    猜你喜欢
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 2013-05-19
    • 2020-01-25
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多