我理解当一个模块包含在一个类中时,它的行为就像它所包含的类的直接超类。
但是,如果同一个班级中包含多个模块怎么办?如果模块之间没有关系,哪一个现在是直接超类?
如果模块A包含模块B(因此在某种程度上存在关系),会覆盖它的一些方法,现在A和B都包含在同一个类中。该类现在是否定义了A和B中的所有方法,以及A和B共有的方法,它只使用A覆盖的方法吗?
答案 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
,那么
A′
C
的直接超类(大概是Object
,但可能是任何东西)变成A′
的超类A′
成为C
的超类A
中包含的模块和A
中包含的模块中包含的模块等等......:
B′
A′
的直接超类成为B′
的超类B′
成为A′
的超类B
中包含的模块以及B
中包含的模块中包含的模块等等...... 覆盖了它的一些方法,现在A和B都包含在同一个类中。
您不能同时包含A
和B
。 Ruby将检查模块是否已经在祖先链中,并且只包含一次。由于包含A
已包含B
,因此您无法再次添加B
。
该类现在是否定义了A和B中的所有方法,以及A和B共有的方法,它只使用A覆盖的方法?
该类没有定义任何方法。从模块继承并不会神奇地定义任何方法。它只是使模块成为超类,就是它。
请不要让Class#superclass
的返回值混淆你:它不返回类的超类指针,而是返回最近的非超类的超类类。