对象如何知道const_get方法?

4
我正在阅读另一个问题,其中提到使用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 方法?
3个回答

6
这是一个源于对象类和对象的单例类之间分离不明确的问题,单例类是一种影子类,每个类都用它来处理这样的事情。在Ruby 2.5+中,您可以使用singleton_class方法轻松访问它:
Object.singleton_class.ancestors
# => [#<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

在这里,Module 出现了,这就是这些方法被混合并可以通过 Object 调用的方式。
相比之下,Object 的继承链相对较为单调。
Object.ancestors
#=> [Object, Kernel, BasicObject]

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


啊!我想我看错了祖先链!查看Object的祖先链误导了我,因为Object是一个类,所以祖先链将显示哪些方法可用于该类的实例,对吧?但是Object也有一个单例类(像所有对象一样),检查该祖先链将显示哪些方法可用于实际对象Object - mbigras
1
我喜欢你如何使用Object#singleton_class,这让我恍然大悟!你能否提到两个不同的祖先链,一个是针对Object,另一个是针对Object.new?检查Object.singleton_class.ancestorsObject.new.singleton_class.ancestors可以回答关于is_a?的问题。 - mbigras

1
我认为你的困惑源于同时从两个方向看待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类的一个实例,而String在其祖先链中有Kernel,所以'pancakes'有一个object_id方法。


0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接