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

sri*_*ira 2 ruby singleton

根据定义,对象的单例类也会继承该对象的超类的单例类。rubyBasicObject中没有任何超类,因为它是最基本的级别类

>> BasicObject.superclass
=> nil
Run Code Online (Sandbox Code Playgroud)

但是当相同的方法调用其单例类时,结果是:

>> BasicObject.singleton_class.superclass
=> Class

Run Code Online (Sandbox Code Playgroud)

为什么 ruby​​ 中没有其他对象将该Class类作为其超类?

BasicObject 的超类 singleton_class 背后的逻辑是如何在 Ruby 中实现的?

Jör*_*tag 6

一般来说,对象的单例类的超类就是该对象的类。即对于foo具有单例类的任何对象,以下内容成立:

foo.singleton_class.superclass == foo.class
Run Code Online (Sandbox Code Playgroud)

然而,对于类来说,这有点无聊:每个类的类都是Class,因此每个类的单例类的超类总是Class

这并不是特别有用,因为它会打破一些合理的假设。例如,如果我有这样的东西:

class Super
  def self.super_singleton_method; end
end

class Sub < Super; end
Run Code Online (Sandbox Code Playgroud)

我希望能够打电话Sub.super_singleton_method。然而,为了做到这一点,Super.singleton_class需要位于 的方法查找链中的某个位置Sub.singleton_class

所以,对于类来说,规则有些不同:一个类的单例类的超类是该类的超类的单例类。即对于任何类Foo,以下内容成立:

Foo.singleton_class.superclass == Foo.superclass.singleton_class
Run Code Online (Sandbox Code Playgroud)

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

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

因此,正如您所看到的,该属性确实适用于除 之外的所有类BasicObject

为什么BasicObject不同的简单答案是它BasicObject没有超类,因此我们不能应用该规则。因此,我们依赖于所有对象的更一般规则

foo.singleton_class.superclass == foo.class
Run Code Online (Sandbox Code Playgroud)

因此,AndBasicObject的类是Class

BasicObject.singleton_class.superclass == BasicObject.class
BasicObject.singleton_class.superclass == Class
Run Code Online (Sandbox Code Playgroud)

为什么 ruby​​ 中没有其他对象将该Class类作为其超类?

继承的唯一原因Class是重写继承或方法查找在 Ruby 中的工作方式。但 Ruby 不允许覆盖这一点。继承和方法查找的工作方式是语言规范的一部分,无法更改。因此,继承Class自是非法的:

class MyClass < Class; end
# can't make subclass of Class (TypeError)
Run Code Online (Sandbox Code Playgroud)

因此,除了类的单例类之外,不可能有任何对象具有Class其超类。(Ruby 当然可以打破自己的规则,因为它是制定规则的人。)

BasicObject 的超类 singleton_class 背后的逻辑是如何在 Ruby 中实现的?

事实并非如此。您无法解释它在 Ruby 中是如何工作的,因为它是 Ruby 本身定义的一部分。

它类似于 的Class子类Module,但它Module是一个类,即 的实例Class。您无法使用 Ruby 的规则从 Ruby 内部解释这一点,但是 Ruby 实现当然可以进行一些设置以使其正常工作,因为 Ruby 实现本身不必遵守 Ruby 的规则:它是唯一的执行规则,因此它可以选择不为自己执行规则。


Ste*_*fan 5

\n

根据定义,对象的单例类也会继承该对象的超类的单例类。

\n
\n

我们不要认为这是理所当然的,而是要弄清楚为什么要这样实现。

\n

在 Ruby 中,有实例方法和类方法。然而,类方法实际上是单例类的实例方法:

\n
class MyClass\n  def foo\n  end\n\n  def self.bar\n  end\nend\n\nMyClass.instance_methods(false)\n#=> [:foo]\n\nMyClass.singleton_class.instance_methods(false)\n#=> [:bar]\n
Run Code Online (Sandbox Code Playgroud)\n

如图所示:

\n
MyClass  --->  #<Class:MyClass>\nfoo            bar\n
Run Code Online (Sandbox Code Playgroud)\n

现在,如果您创建一个子类MySubClass,它会从其超类继承实例方法和类方法MyClass

\n
class MySubClass < MyClass\nend\n\nMySubClass.instance_methods\n#=> [:foo, ...]\n\nMySubClass.singleton_class.instance_methods\n#=> [:bar, ...]\n
Run Code Online (Sandbox Code Playgroud)\n

为了实现这一点,必须为类和单例类建立继承:

\n
class MyClass\n  def foo\n  end\n\n  def self.bar\n  end\nend\n\nMyClass.instance_methods(false)\n#=> [:foo]\n\nMyClass.singleton_class.instance_methods(false)\n#=> [:bar]\n
Run Code Online (Sandbox Code Playgroud)\n

Ruby 在内部对此进行了优化 \xe2\x80\x93 单例类仅在需要时创建。但从概念上讲,这就是发生的情况。

\n

除此之外,MyClassMySubClass已经附带了一些内置的类方法,最值得注意的.new是用于创建实例,但也.superclass.

\n

您可能知道.new调用的默认实现.allocate的默认实现。因此,某个地方必须有一种包含这些方法的“根类”。由于它们是类方法,因此它必须位于单例类一侧的顶部:

\n
MyClass  --->  #<Class:MyClass>\nfoo            bar\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
Class.instance_methods(false)\n#=> [:allocate, :superclass, :subclasses, :new]\n
Run Code Online (Sandbox Code Playgroud)\n