首页 > 解决方案 > Ruby祖先方法问题

问题描述

考虑以下示例:

module M
end

class C
  include M
end

c = C.new
p c.singleton_class.ancestors

输出是:[#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]

但是现在如果我们将模块包含在对象 c 的 singleton_class 中,如下所示

class << c
  include M 
  p ancestors
end

输出是:[#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]

但是The well-grounded Rubyist书上说第13章应该是这样的Object individual

[#<Class:#<C:0x000055b6b069c5f0>>, M, C, M, Object, Kernel, BasicObject]

标签: rubyobjectsingleton

解决方案


要回答这个问题,我们需要了解 include 是如何工作的。 Module#include

以相反的顺序对每个参数调用#append_features。

Module#append_features

如果此模块尚未添加到 mod 或其祖先之一,则将此模块的常量、方法和模块变量添加到 mod。

如果您交换包含模块的顺序,您将获得预期的结果

module M
end

class C
end

c = C.new

p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, C, Object, Kernel, BasicObject]
class << c
  include M 
end

p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, Object, Kernel, BasicObject]
# M is not in the ancestors of the class C is ancestors of the singleton class

class C
  include M
end

p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, M, Object, Kernel, BasicObject]
# The include statement put M as first ancestors of C

如果我们改变顺序

module M
end

class C
end

c = C.new

p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, Object, Kernel, BasicObject]

class C
  include M
end

p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is ancestor of C and of the singleton class #C

class << c
  include M 
end

p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is not included

推荐阅读