2010-01-26 9 views
6

In Ruby könnten wir super innerhalb der Singleton-Methode verwenden, um die Singleton-Methode der entsprechenden Superklasse aufzurufen, wie der folgende Code zeigt.Wie ist die Beziehung zwischen der Metaklasse der Basis und der abgeleiteten Klasse in Ruby?

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 

aber ich nicht ganz scheinen zu bekommen, wie das Gespräch super innerhalb Derived.class_method konnte Base.class_method erreichen. Ich nehme an, dass class_method auf ihrer Metaklasse definiert ist, bedeutet das, dass ihre Metaklasse eine Eltern/Kind-Beziehung hat? (Ich kann nicht ganz bestätigen, dass durch Experimente)

aktualisieren: Ich stelle diese Frage, weil ich sehe, erinnerte irgendwo es irgendeine Art von Beziehung bettwen Basis und abgeleiteten Klasse metaclass (aber ich kann nicht finde es nicht mehr). Zusätzlich zu wissen, wie eigentlich super funktioniert, möchte ich auch bestätigen, ob die beiden Metaklassen völlig getrennt sind oder nicht.

Antwort

11

Es gibt vier Klassenobjekte im Spiel hier:

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

Nomenklatur:

  • < ...> ist die Klasse von jedem Objekt.
  • Der Name der Klasse ist in der zweiten Zeile.
  • Wenn der Name mit # beginnt, ist es die Eigenklasse (Singleton-Klasse).
  • Superpunkte auf eine Klasse der Superklasse
  • Klasse zeigt auf die Klasse der Klasse.

Wenn Sie Derived.class_method nennen, folgt Ruby den „richtigen und dann nach oben“ Regel: Zuerst auf die Klasse des Objekts aufrufen und dann die Superkette verfolgen, zu stoppen, wenn die Methode gefunden wird:

  • Der Empfänger des Aufrufs "class_method" ist abgeleitet. Folge also der Kette nach dem Klassenobjekt von Derived, das ist seine Eigenklasse (#Derived).
  • Abgeleitet definiert die Methode nicht, also folgt Ruby der Kette nach oben in die #klasse von # Derived, die #Base ist.

  • Das Verfahren ist dort zu finden, so Rubin die Nachricht an # Base.class_method

Sie entsendet glaubt nicht, dass ich dieses Zeug aus der Spitze von meinem Kopf wusste, nicht wahr? Hier ist, wo mein Gehirn all diese Meta Juju: Metaprogramming Ruby.

Teil 2. Wie eine „Eigenklasse“ machen (auch bekannt als „Singletonklasse“) kommt

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

Dieses Verfahren die Eigenklasse eines Objekts zurückkehren wird. Nun, was ist mit Klassen? Das sind auch Objekte.

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

Hinweis: Oben ist von Ruby1.9. Wenn unter Ruby 1 ausgeführt.8, erhalten Sie eine Überraschung:

p Derived.eigenclass.superclass # => #<Class:Class> 
+0

Gibt es eine Möglichkeit zu 'sehen', die die Beziehung zwischen #Base und #Derived? z.B. wie die normale '.superclass'. – bryantsai

+0

Ich habe den Trick hinzugefügt, der eine Eigenklasse aus dem Versteck holt. Aber das Diagramm ist nicht konsistent mit dem, was der Trick zeigt :( –

+0

gut ... # ist nicht # , das ist mein Problem ... Dosis die Verbindung von #Derived zu #Base wirklich existieren? – bryantsai

3

Dieses Diagramm, das die Beziehung erklärt: http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

Auch hier sind einige andere Beiträge, die mehr die Feinheiten der eigenclasses erklären: http://www.klankboomklang.com/2007/10/05/the-metaclass/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

Und hier ist eine ziemlich hartnäckige, die mehr erklärt, als Sie wahrscheinlich gerne wissen würden: http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

+1

Endlich bin ich dazu gekommen, deinen harten Post zu lesen. Tolles Zeug! –

4

Um zu klären und zu korrigieren, was ich in den Kommentaren in Bezug auf die Art und Weise schrieb Rubin versteckt/aussetzt eigenclasses, hier ist die Situation: gibt

(1) Die Object#class Methode immer die ersten real:

Ruby 1.8 (nicht Eigenklasse oder iclass) Oberklasse der tatsächlichen Klasse eines Objekts. z

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

Mit anderen Worten, die Object#class Methode wird nie eine Eigenklasse zurückkehren, geht es über sie und stattdessen gibt die erste ‚echte‘ Klasse in der Vererbungshierarchie findet.

(2) Die Class#superclass Methode hat zwei Fälle. Wenn der Empfänger keine Eigenklasse ist, gibt er einfach die Oberklasse zurück. Wenn jedoch der Empfänger eine Eigenklasse ist, dann gibt diese Methode die tatsächliche Klasse (nicht notwendigerweise real) des Empfängers zurück.

# 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 

Von oben Class#superclass verhält sich wie bei einer normalen Klasse zu erwarten, sondern auch für die Eigenklasse Beispiel heißt es, die übergeordnete Klasse der Eigenklasse des Moduls ist Klasse, die nicht wahr ist. Aus diesem Diagramm http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/ wissen wir, dass die Oberklasse der Eigenklasse von Modul tatsächlich die Eigenklasse von Object ist. Ich bin mir nicht sicher, warum Ruby 1.8 dieses seltsame Verhalten hat.

Ruby 1.9:

(1) Die Object#class Verfahren verhält sich identisch zu der Version 1.8.

(2) Die Class#superclass Methode hat nicht mehr zwei Fälle, sie behandelt jetzt die Eigenklassen genauso wie normale Klassen und gibt die tatsächliche Oberklasse wie erwartet zurück.

beispiel

class << Module; superclass; end #=> #<Class:Object> 
Verwandte Themen