代码之家  ›  专栏  ›  技术社区  ›  bryantsai

Ruby中基类和派生类的元类之间有什么关系?

  •  6
  • bryantsai  · 技术社区  · 15 年前

    在Ruby中,我们可以使用 super 在singleton方法中调用相应的超级类的singleton方法,如下代码所示。

    class Base
      def self.class_method
        puts "Base class method"
      end
    end
    
    class Derived < Base
      def self.class_method
        puts "Derived class method"
        super
      end
    end
    
    Derived.class_method
    # Derived class method
    # Base class method
    

    不过,我好像不太明白这个电话怎么打 超级的 在内部 Derived.class_method 可以达到 Base.class_method . 我认为 class_method 是在他们的元类上定义的,这是否意味着他们的元类有父/子关系?(我不能通过实验来证实这一点)

    更新 我问这个问题是因为我记得看到 在某处 Bettwen基和派生类的元类之间有某种关系(但我再也找不到了)。除了知道 超级的 好的,我还要确认两个元类是否完全独立。

    3 回复  |  直到 15 年前
        1
  •  11
  •   Wayne Conrad    15 年前

    这里有四个类对象:

    <Class>---class---><Class>
    Base               #Base
       ^                  ^
       |                  |
       |                  |
     super              super
       |                  |
       |                  |
    <Class>            <Class>
    Derived---class--->#Derived
    

    术语:

    • <…>是每个对象的类。
    • 类的名称在第二行。
    • 如果名称以开头,它就是eigenclass(又称singleton类)。
    • 超指向类的超类
    • 类指向类的类。

    当您调用derived.class_方法时,ruby遵循“正确的一个然后向上”的规则:首先转到对象的类,然后沿着超类链向上,当找到该方法时停止:

    • 派生“class_method”调用的接收器。所以沿着链的右边到派生的类对象,它是它的本征类(派生的)。
    • 派生没有定义方法,所以Ruby沿着链向上到派生的超类,它是基。

    • 在那里找到了这个方法,所以Ruby将消息发送给base.class_方法

    你不认为我完全不知道这些,是吗?这就是我的大脑得到所有这些元juju的地方: Metaprogramming Ruby .

    第2部分。 如何使一个“本征类”(又称“单体类”)走出隐藏

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

    此方法将返回任何对象的特征类。现在,上课怎么样?这些也是物体。

    p Derived.eigenclass               # => #<Class:Derived>
    p Derived.eigenclass.superclass    # => #<Class:Base>
    p Base.eigenclass                  # => #<Class:Base>
    

    注:以上为1.9卢布。在Ruby1.8下运行时,您会得到一个惊喜:

    p Derived.eigenclass.superclass    # => #<Class:Class>
    
        2
  •  4
  •   horseyguy    15 年前

    为了澄清和纠正我在评论中关于Ruby隐藏/暴露特征类的方式所写的内容,以下是情况:

    红宝石1.8:

    (1) Object#class 方法始终返回 实际的 对象的类。 例如

    o = Object.new
    class << o; end
    o.class #=> returns Object, even though the _actual_ class is the eigenclass of o
    

    也就是说, 对象类 而是返回它在继承层次结构中找到的第一个“real”类。

    (2) Class#superclass 然后此方法返回 实际的 (即不一定是真实的)接收者类别。

    # case where receiver is a normal class (i.e not an eigenclass)
    Module.superclass #=> Object (behaves as expected)
    
    # case where receiver is an eigenclass
    class << Module; superclass; end #=> returns Class, this is NOT the superclass
    

    从上面看, 类超类 在普通类的情况下,其行为与预期一致,但在本征类示例中,它指出模块本征类的超类是类,这不是真的。从这个图表 http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/ 我们知道模件本征类的超类实际上是物体的本征类。我不确定Ruby1.8为什么会有这种奇怪的行为。

    红宝石1.9:

    (1)该 对象类 方法的行为与1.8版本相同。

    (2) 类超类 方法不再有两种情况,它现在处理特征类的方式与处理普通类的方式相同,并按预期返回实际的超类。

    例如

    class << Module; superclass; end #=> #<Class:Object>
    
        3
  •  3
  •   horseyguy    15 年前