为什么单例方法(又称类方法)被继承?

时间:2019-05-04 20:40:07

标签: ruby metaprogramming

我对此行为感到有些惊讶:

puts RUBY_VERSION # 2.4.1
class A
  class << A
    def my_method
      puts self
    end
  end
end

class B < A ; end

puts A.singleton_methods.inspect # [:my_method]
puts B.singleton_methods.inspect # [:my_method]
puts B.my_method # B
puts A.my_method # A

在元编程Ruby 2(惊人的书BTW)中,Paolo Perrota说:

此外,单例类只有一个 实例(即其名称的来源),并且它们不能被继承

但是我们可以看到,该摘要中的类方法是B从A继承的。所以,有人可以解释一下它的工作原理吗?

这种行为意味着类是单例类的实例吗?

(老实说,我在写这本书之前解释了类方法的继承机制之前写过这篇文章。但是现在我理解了,我仍然认为这是一个有趣的话题)

1 个答案:

答案 0 :(得分:2)

为什么类方法被继承?

  1. 每个班级都有单身班级
  2. 当存在继承层次时,单例类继承链将反映以下情况之一: “正常”事件。
  3. 在Ruby方法查找过程中,解释器 遍历单例类的继承链。
puts RUBY_VERSION # 2.4.1
class A
  class << A
    def my_method
      puts self
    end
  end
end

class B < A ; end

puts A.singleton_class == B.singleton_class.superclass # true
puts A == B.superclass # true

因此,在方法查找过程中,解释器转到B的单例类,在其中找不到方法my_method,然后到A的单例类的那里。找到方法并执行。

但是我们应该承认,有两个类的继承链,它们在某种程度上处于竞争状态,这意味着必须首先遍历两个链中的一个。但是,哪一个是正常类之一或单例类中的哪一个?

好吧,如果您知道的更多,请告诉我,但是代码似乎可以告诉您:

puts RUBY_VERSION # 2.4.1

class Class
  def my_method
    puts "Those who seek for gold dig up much earth and find a little."
  end
end

A = Class.new do
  class << self
    def my_method
      puts self
    end
  end
end

class B < A ; end

Class.new.my_method # Those who seek for gold dig up much earth and find a little.
A.my_method # A

如果“普通”继承链优先于单例类的继承链,则A.my_method的结果将与Class.new.my_method相同,因为{{ 1}}是A。如果删除Class的单例方法,我们可以更清楚地看到它:

A

这种行为意味着类是单例类的实例吗?

我真的很想回答这个问题。但是我不太确定。难道不就意味着puts RUBY_VERSION # 2.4.1 class Class def my_method puts "Those who seek for gold dig up much earth and find a little." end end A = Class.new do # class << self # def my_method # puts self # end # end end class B < A ; end Class.new.my_method # Those who seek for gold dig up much earth and find a little. A.my_method # Those who seek for gold dig up much earth and find a little. 既是A的实例又是它自己的单例类?双重继承!?

如果您了解得更多,请分享您的知识。这是一个非常有趣的话题:)