【问题标题】:Ruby eigenclass unexpected behaviourRuby eigenclass 意外行为
【发布时间】:2014-07-24 10:08:23
【问题描述】:

首先,让我们添加一个方法来检索“从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>

我期待第二次 put 输出 Class

知道为什么会这样吗?

【问题讨论】:

    标签: ruby metaprogramming eigenclass


    【解决方案1】:

    puts A.new.eigenclass.superclass,您实际上是在 A 类的实例上调用 #eigenclass。我将从背景故事开始解释 eigenclass 的实际工作原理,然后继续讲述正在发生的事情在你的代码中。

    背景故事:

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

    所以对于obj = Foo.new,类层次结构实际上是这样的:

    obj --eigenclass--> #> --(超类)--> A

    代替:

    obj --(class)--> A

    在你用#eigenclass劫持self后可以产生一个隐藏类。

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

    A --(eigenclass)--> # --(超类)--> #

    现在它显示 # 而不是 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的超类的本征类。

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

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

    问候

    【讨论】:

    • 我想你的意思是 A.eigenclass.superclass== Object.eigenclass
    • 是的,对不起。无意中错过了。
    • 我喜欢你放置 USB 数据线的方式,让它看起来像一个正在欣赏你的画的火柴人。 +1(对于答案,而不是火柴人)。
    【解决方案2】:

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

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

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

    A.new.eigenclass.superclass      # => A                               
    

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

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

    A 的超类和 Class.new 的超类都隐含为Object

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

    因为 A 的超类是 Object,所以 A 的 eigenclass 的超类是 Object 的 eigenclass。

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

    类似地,找到Class.new 的特征类的超类会产生 Object 的特征类

    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>
    

    【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-28
      • 2014-09-03
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-02
      相关资源
      最近更新 更多