【问题标题】:How does Object know about the const_get method?Object 如何知道 const_get 方法?
【发布时间】:2018-09-26 18:40:25
【问题描述】:

我正在阅读 another questionanswer,其中提到使用 Module#const_get 实例方法在模块中查找类。例如:

module M
  class C
  end
end

p M.const_get 'C'
#=> M::C

我对@9​​87654325@的方法很好奇所以我用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

这让我很困惑,因为我知道 ModuleObject,但 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 方法的?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    这是一个对象的类和对象的单例类之间被误解的分离的产物,这是每个类用于此类事情的一种影子类。

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

    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 也有一个单例类(像所有对象一样),并且检查祖先链将显示哪些方法可用于实际对象Object
    • 我喜欢你使用Object#singleton_class 的方式,这对我有帮助!您能否提及两个不同的祖先链,一个用于Object,一个用于Object.new?检查Object.singleton_class.ancestorsObject.new.singleton_class.ancestors 回答了关于is_a? 的问题
    【解决方案2】:

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

    1. Object 是一个类,因此Object.ancestors 可用于查看继承层次结构。这告诉您Object &lt; Kernel 为真,Object &lt; 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 #=&gt; true

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

    2. Object 是如何知道const_get 方法的?

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

    【讨论】:

      【解决方案3】:

      Object.is_a? Module #=&gt; true

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

      Module#const_get

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-18
        • 2018-05-28
        • 2011-09-24
        • 2018-11-08
        • 1970-01-01
        相关资源
        最近更新 更多