BasicObject的singleton_class的超类在Ruby中如何以及为什么是Class类?

brccelvz  于 2022-12-22  发布在  Ruby
关注(0)|答案(2)|浏览(160)

根据定义,对象的单例类也继承了对象超类的单例类,ruby中的BasicObject没有超类,因为它是最基本的类

>> BasicObject.superclass
=> nil

但是当同一个方法调用它的单例类时,结果是:

>> BasicObject.singleton_class.superclass
=> Class

还有为什么Ruby中没有其他对象将Class类作为超类?
BasicObject的singleton_class的超类背后的逻辑是如何在Ruby中实现的?

1hdlvixo

1hdlvixo1#

一般来说,对象的单例类的超类就是对象的类,也就是说,对于任何一个有单例类的对象foo,下面的公式成立:

foo.singleton_class.superclass == foo.class

然而,对于类来说,这会有些无聊:每个类的类都是Class,所以每个类的单例类的超类总是Class
这不是特别有用,因为它会打破一些合理的假设,例如,如果我有这样的东西:

class Super
  def self.super_singleton_method; end
end

class Sub < Super; end

我希望能够调用Sub.super_singleton_method,但是,为了做到这一点,Super.singleton_class需要位于Sub.singleton_class的方法查找链中的某个位置。
因此,对于类,规则有些不同:类的单例类的超类是该类的超类的单例类,即对于任何类Foo,以下成立:

Foo.singleton_class.superclass == Foo.superclass.singleton_class

如果需要,可以检查系统中的每个类是否都是这样:

ObjectSpace.each_object(Class).select do |klass|
  klass.singleton_class.superclass != klass.superclass.singleton_class
end
#=> [BasicObject]

因此,正如您所看到的,这个属性 * 确实 * 适用于 * 除BasicObject * 之外的所有类。
BasicObject不同的原因很简单,因为BasicObject没有超类,因此我们不能应用这个规则。

foo.singleton_class.superclass == foo.class

BasicObject的类是Class,因此,

BasicObject.singleton_class.superclass == BasicObject.class
BasicObject.singleton_class.superclass == Class

还有为什么Ruby中没有其他对象将Class类作为超类?
Class继承的唯一原因是为了覆盖Ruby中继承和方法查找的工作方式,但是Ruby不允许覆盖这一点。继承和方法查找的工作方式是语言规范的一部分,不能更改。因此,从Class继承是非法的:

class MyClass < Class; end
# can't make subclass of Class (TypeError)

因此,不可能有任何对象以Class作为其超类,* 除了 * 类的单例类(Ruby当然可以打破自己的规则,因为它是制定规则的人)。
BasicObject的singleton_class的超类背后的逻辑是如何在Ruby中实现的?
你无法解释这在Ruby中是如何工作的,因为这是Ruby本身定义的一部分。
这类似于ClassModule的子类,但是Module是一个类,也就是Class的一个示例,你不能用Ruby的规则来解释这一点,但是Ruby的实现当然可以设置一些东西来使它工作,因为Ruby的实现本身不必遵守Ruby的规则:它是执行规则的一方,因此它可以选择不为自己执行规则。

drkbr07n

drkbr07n2#

根据定义,对象的单例类也继承了对象超类的单例类。
我们不要想当然地认为这是理所当然的,让我们弄清楚为什么要以这种方式实现它。
在Ruby中,有示例方法和类方法,而类方法实际上是单例类的示例方法:

class MyClass
  def foo
  end

  def self.bar
  end
end

MyClass.instance_methods(false)
#=> [:foo]

MyClass.singleton_class.instance_methods(false)
#=> [:bar]

如图所示:

MyClass  --->  #<Class:MyClass>
foo            bar

现在,如果你创建一个子类MySubClass,它会从超类MyClass继承示例方法和类方法:

class MySubClass < MyClass
end

MySubClass.instance_methods
#=> [:foo, ...]

MySubClass.singleton_class.instance_methods
#=> [:bar, ...]

为了让它工作,必须为类和单例类都建立继承:

MyClass     --->  #<Class:MyClass>
foo               bar
    ^                    ^
    |                    |
MySubClass  --->  #<Class:MySubClass>

Ruby在内部对此进行了优化--单例类只在需要的时候创建,但从概念上讲,这就是发生的事情。
除此之外,MyClassMySubClass已经带有一些内置的类方法,最著名的是用于创建示例的.new,还有.superclass
你可能知道.new的默认实现是在幕后调用.allocate的,所以在某个地方一定有一个包含这些方法的“根类”,因为它们是类方法,所以它必须位于单例类的顶部:

<singleton root class>
                  new
                  allocate
                  superclass
                         ^
                         |
                        ...
                         |
MyClass     --->  #<Class:MyClass>
foo               bar
    ^                    ^
    |                    |
MySubClass  --->  #<Class:MySubClass>

这个神秘的顶级单例根类为所有其他类提供了基本的类方法,它是... Class

Class.instance_methods(false)
#=> [:allocate, :superclass, :subclasses, :new]

相关问题