我正在阅读另一个问题,其中的答案提到使用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
这让我感到困惑,因为我知道Module
是Object
但Object
不是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
:
Object
是一个类,因此Object.ancestors
可用于查看继承层次结构。这告诉你Object < Kernel
是真的,Object < Module
是假的。- Ruby 中的类也是对象,具体来说,它们是
Class
类的实例。这告诉您Object.is_a? Class
和Object.is_a? Module
的方式与'pancakes'.is_a? String
相同。该Object.const_get
是方法调用,就像'pancakes'.upcase
是方法调用一样。
您可以将some_obj.is_a? SomeClass
视为some_obj.class.ancestors.include? SomeClass
的简短表达方式。
回答您的具体问题:
-
如果
Module
不在Object
的祖先链中,为什么Object.is_a? Module #=> true
?因为
is_a?
和ancestors
正在看待不同的东西。 -
Object
如何知道const_get
方法?因为
Object
是Class
类的实例,Class
在其祖先中包含Module
。类似于'pancakes'
是String
类的一个实例,它的祖先Kernel
'pancakes'
因此具有object_id
方法。
Object.is_a? Module #=> true
is_a?
在问Object
是否是Module
的实例(或专用实例)。Class
是Module
的一个子类,因此Class
的所有实例实际上只是Module
的专用实例。由于Object
是Class
的实例,因此Object
也是Module
的实例。
Module#const_get
const_get
是在Module
类中定义的实例方法。由于Object
是Module
的实例(出于上述原因),因此它有权访问Module#const_get
。