2010-07-18 11 views
6

Ich versuche, eine Instanz eines Merkmals Dies funktioniertWie erstelle ich eine Instanz eines Merkmals in einer generischen Methode in scala?

val inst = new Object with MyTrait 

gut mit dieser Methode zu schaffen, aber ich möchte in, das heißt auf eine Generatorfunktion diese Schöpfung bewegen.

object Creator { 
    def create[T] : T = new Object with T 
} 

Ich werde natürlich das Manifest müssen irgendwie die Art Löschung Probleme zu beheben, aber bevor ich das bekommen, ich laufe in 2 Fragen:

  1. Selbst mit einem impliziten Manifest Scala verlangt immer noch, dass T ein Merkmal ist. Wie füge ich eine Einschränkung hinzu, um [T] zu erstellen, so dass T ein Merkmal ist?

  2. Wenn ich die Methode Class.newInstance verwenden möchte, um die Instanz dynamisch zu erstellen, anstatt "neu" zu verwenden, wie würde ich das "mit" in "neues Objekt mit T" angeben? Ist es möglich, zur Laufzeit dynamisch neue Beton-Mixin-Typen zu erstellen?

Antwort

8

Sie dies nicht tun können (auch mit einem Manifest). Der Code new Object with T umfasst das Erstellen einer neuen anonymen Klasse, die die Kombination Object with T darstellt. Um dies an Ihre create-Funktion zu übergeben, müssten Sie diese neue Klasse (mit neuem Bytecode) zur Laufzeit generieren, und Scala hat keine Möglichkeit, zur Laufzeit eine neue Klasse zu generieren.

Eine Strategie könnte sein, zu versuchen, die spezielle Funktionalität der Factory-Methode stattdessen in den Konstruktor der Klasse zu übertragen und dann den Konstruktor direkt zu verwenden.

Eine andere mögliche Strategie besteht darin, Konvertierungsfunktionen (implizit oder anders) zu den Merkmalen zu erstellen, die Sie mit dieser Klasse verwenden möchten.

+0

Dies scheint eine interessante Einschränkung der Sprache zu sein, aber ich sehe keinen Grund, warum es nicht mit einer neuen "dynamischen" Mixin-Unterstützung in Scala behoben werden konnte. Der Eigenschaftscode ist bereits als statische Methode verfügbar, so dass die Linearisierungssuche zur Laufzeit statt in den Klassenbytecode integriert werden konnte. Dann müssten Sie nur die Überprüfung des Laufzeittyps hinzufügen, damit "asInstanceOf" funktioniert. – ACyclic

14

Ich bin nicht sicher, was die Motivation für Ihre Frage ist, aber Sie könnten eine Fabrik für T als impliziten Parameter übergeben. Dies ist bekannt unter Verwendung von Typklassen oder Ad-hoc-Polymorphismus.

object Test extends Application { 
    trait Factory[T] { 
    def apply: T 
    } 
    object Factory { 
    /** 
    * Construct a factory for type `T` that creates a new instance by 
    * invoking the by-name parameter `t` 
    */ 
    def apply[T](t: => T): Factory[T] = new Factory[T] { 
     def apply = t 
    } 
    } 

    // define a few traits... 
    trait T1 
    trait T2 

    // ...and corresponding instances of the `Factory` type class. 
    implicit val T1Factory: Factory[T1] = Factory(new T1{}) 
    implicit val T2Factory: Factory[T2] = Factory(new T2{}) 

    // Use a context bound to restrict type parameter T 
    // by requiring an implicit parameter of type `Factory[T]` 
    def create[T: Factory]: T = implicitly[Factory[T]].apply 

    create[T1] 
    create[T2] 

} 

Am anderen Ende des Spektrums, können Sie den Compiler zur Laufzeit aufrufen, wie in this answer auf die Frage detailliert „Dynamic mixin in Scala - ist es möglich“.

+0

Danke, ich muss vielleicht diese Methode verwenden. Mein Anwendungsfall ist der Java-Proxy. Ich möchte eine Bibliothek schreiben, die remotable ist. Ich muss daher Schnittstellen für alle meine Klassen definieren, was ein Schmerz ist, da ich alles aufdecken möchte. Eine Lösung ist, alles als Merkmal zu schreiben, dann bekomme ich die Schnittstellendefinition kostenlos. Der Zweck der create-Funktion besteht darin, ein Merkmal auf der "konkreten" Seite der Proxy-Verbindung zu instanziieren. – ACyclic

Verwandte Themen