Ruby eigenclass意外行为

时间:2014-06-03 22:16:55

标签: ruby metaprogramming eigenclass

首先,让我们添加一个方法来检索“从this blog post复制的本征类”

class Object 
  def eigenclass 
    class << self
      self
    end 
  end 
end

然后创建一个简单的类

class A
end

puts A.new.eigenclass.superclass      # => A
puts Class.new.eigenclass.superclass  # => #<Class:Object>

我期待第二次投放 Class

有什么理由发生这种情况?

3 个答案:

答案 0 :(得分:5)

通过puts A.new.eigenclass.superclass,您实际上是在A类的实例上调用#eigenclass。我将从背景故事开始解释eigenclass实际上是如何工作的,然后将继续告诉您代码中发生了什么。

<强>背景故事:

EigenClass 是一个隐藏类,其中包含仅适用于该特定对象的单例方法。

因此,对于obj = Foo.new,类层次结构实际上如下所示:

  

obj --eigenclass - &gt; #&GT; - (超) - &GT;甲

而不是:

  

obj - (类) - &gt;甲

使用#eigenclass劫持自我后,可以生成隐藏的类。

现在,在Ruby中,是一个对象。这也意味着#eigenclass也应该显示隐藏的本征类A(其中保留了A的sigleton方法)。

  

A - (本征类) - &gt; # - (超类) - &gt; #

现在它显示而不是A的原因是因为Ruby以非常漂亮的模式组织了类,超类和特征类。这可以用示例显示,而不是用令人困惑的词语引用它:

A.superclass #=> Object   
A.eigenclass #=> #<Class: A>   
A.eigenclass.superclass #=> #<Class: Object> => Eigenclass of Object   
A.eigenclass.superclass == Object.eigenclass #=> true   

的特征类的超类是原始的超类的本征类。

现在,来看你的案例:Class.new.eigenclass.superclass,现在这是不言自明的。 Class.new对应一个新的匿名类,比如B,您实际上正在调用eigenclass.superclass。由于B的超类是Object,因此B的本征类的超类是B的超类的本征类。

尽我所能用例子解释。请在下面的评论中进一步澄清;将相应更新答案。补充(来自Pragmatic MR):Shot from Pragmatic MR

在上图中,D继承自C。所以D.eigenclass.superclass是(D的超类)[即C]的eigneclass。现在C的超类是Object ..所以逻辑也一样。

此致

答案 1 :(得分:4)

从该博文中,您可以构建一个类似的图表:

                        +------------------+               +-------------------+
                        |      Object      |- eigenclass ->| Object eigenclass |
                        +------------------+               +-------------------+
                                 ^                                   ^             
                                 | superclass             superclass |                                                     
                        +------------------+               +-------------------+
                        |        A         |- eigenclass ->|    A eigenclass   |
                        +------------------+               +-------------------+
                                 ^
                                 | superclass
+-------+               +------------------+                                   
| A.new |- eigenclass ->| A.new.eigenclass |                                   
+-------+               +------------------+    

试图找到A实例的特征类的超类,表明它指向A类。

A.new.eigenclass.superclass      # => A                               

Class.new返回Class对象的实例,即新类。这是一个类,就像A类一样。

Class.new.class # => Class
A.class         # => Class

A&#39的超类和Class.new的超类都隐含Object

Class.new.superclass # => Object
A.superclass         # => Object

因为A的超类是Object,所以A&#39的超类是对象的特征类。

Object.eigenclass                            # => #<Class:Object>
A.eigenclass.superclass                      # => #<Class:Object>
A.eigenclass.superclass == Object.eigenclass # => true

类似地,找到Class.new的本征类的超类产生对象的本征类

Class.new.eigenclass.superclass              # => #<Class:Object>

Class.newA.new之间的区别在于Class.new本身就是一个类,因此可以构建新对象,而A.new则不能。

Class.new.new # => #<#<Class:0x007f86b50d8f70>:0x007f86b50d8f20>
A.new.new     # => NoMethodError: undefined method `new' for #<A:0x007f86b50cbf50>

答案 2 :(得分:1)

一个类的本征类对于类的祖先有一个完整的特征类阴影层次结构,它们都在本征类和类之间。这是因为期望类继承其祖先的类方法。例如,如果您执行了def Numeric.kind_of_number?() true end,则您希望Fixnum.kind_of_number?为真。所以你需要将Numeric的本征类作为Fixnum的本征类的祖先。