对象如何知道const_get方法?



我正在阅读另一个问题,其中的答案提到使用Module#const_get实例方法在模块中查找类。例如:

module M
class C
end
end
p M.const_get 'C'
#=> M::C

我对const_get方法很好奇,所以我使用了ri并发现:

ri Module#const_get
...
This method will recursively look up constant names if a namespaced
class name is provided.  For example:
module Foo; class Bar; end end
Object.const_get 'Foo::Bar'
...

似乎Object::const_get是一种单例方法。在我们的上下文中使用它适用于:

module M
class C
end
end
p Object.const_get 'M::C'
#=> M::C

但是没有关于这种单例方法的记录:

ri Object::const_get
Nothing known about Object::const_get
ri Object.const_get
Nothing known about Object.const_get

这让我感到困惑,因为我知道ModuleObjectObject不是Module

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

除此之外,我使用Object#is_a?实例方法来检查并发现我错了:

Module.is_a? Object
#=> true
Object.is_a? Module
#=> true

最初是一个无辜的ri查询,这让我对整个 Ruby 对象模型感到困惑。

  • 如果Module不在Object祖先链中,为什么Object.is_a? Module #=> true
  • Object如何知道const_get方法?

这是对象的类和对象的单例类之间不被理解的分离的工件,这是每个类用于此类操作的一种影子类。

您可以使用singleton_class方法在 Ruby 2.5+ 中轻松访问它:

Object.singleton_class.ancestors
# => [#<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

Module在这里出现的地方,所以这就是这些方法混合在一起的方式,并且可以通过Object调用。

对象本身有一个相对沉闷的继承链:

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

Ruby中的每个对象都有一个类,即使Class是一个Object,它也有一个关联的Class

我认为您的困惑源于同时从两个方向看待Object

  1. Object是一个类,因此Object.ancestors可用于查看继承层次结构。这告诉你Object < Kernel是真的,Object < Module是假的。
  2. Ruby 中的类也是对象,具体来说,它们是Class类的实例。这告诉您Object.is_a? ClassObject.is_a? Module的方式与'pancakes'.is_a? String相同。该Object.const_get是方法调用,就像'pancakes'.upcase是方法调用一样。

您可以将some_obj.is_a? SomeClass视为some_obj.class.ancestors.include? SomeClass的简短表达方式。

回答您的具体问题:

  1. 如果Module不在Object的祖先链中,为什么Object.is_a? Module #=> true

    因为is_a?ancestors正在看待不同的东西。

  2. Object如何知道const_get方法?

    因为ObjectClass类的实例,Class在其祖先中包含Module。类似于'pancakes'String类的一个实例,它的祖先Kernel'pancakes'因此具有object_id方法。

Object.is_a? Module #=> true

is_a?在问Object是否是Module的实例(或专用实例)。ClassModule的一个子类,因此Class的所有实例实际上只是Module的专用实例。由于ObjectClass的实例,因此Object也是Module的实例。

Module#const_get

const_get是在Module类中定义的实例方法。由于ObjectModule的实例(出于上述原因),因此它有权访问Module#const_get

最新更新