2010-07-18 7 views
6

Je suis en train de créer une instance d'un trait en utilisant cette méthodeComment créer une instance d'un trait dans une méthode générique dans scala?

val inst = new Object with MyTrait 

Cela fonctionne bien, mais je voudrais passer cette création à une fonction de générateur, à savoir.

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

Je vais évidemment avoir besoin manifeste de corriger en quelque sorte les problèmes d'effacement de type, mais avant de passer à cela, je courir pour 2 questions:

  1. Même avec un manifeste implicite , Scala exige toujours que T soit un trait. Comment puis-je ajouter une restriction pour créer [T] afin que T soit un trait?

  2. Si j'ai choisi d'utiliser la méthode Class.newInstance pour créer dynamiquement l'instance plutôt que d'utiliser "new", comment est-ce que je spécifierais le "with" dans "new Object with T"? Est-il possible de créer dynamiquement de nouveaux types de mixin concrets lors de l'exécution?

Répondre

8

Vous ne pouvez pas le faire (même avec un manifeste). Le code new Object with T implique la création d'une nouvelle classe anonyme représentant la combinaison de Object with T. Pour passer cela à votre fonction create, vous devez générer cette nouvelle classe (avec un nouveau bytecode) lors de l'exécution, et Scala n'a pas les moyens de générer une nouvelle classe à l'exécution.

Une stratégie pourrait être d'essayer de transférer à la place la fonctionnalité spéciale de la méthode usine dans le constructeur de la classe, puis d'utiliser directement le constructeur.

Une autre stratégie possible consiste à créer des fonctions de conversion (implicites ou non) pour les caractères que vous souhaitez utiliser avec cette classe.

+0

Cela semble être une limitation intéressante du langage, mais je ne vois pas pourquoi il ne pourrait pas être résolu avec un nouveau support de mixage "Dynamique" dans Scala. Le code de trait est déjà disponible en tant que méthodes statiques, de sorte que la recherche de linéarisation peut être calculée au moment de l'exécution plutôt que cuite dans le bytecode de classe. Ensuite, vous devez juste ajouter un contrôle de type à l'exécution pour que "asInstanceOf" fonctionne. – ACyclic

14

Je ne suis pas sûr de savoir quelle est la motivation de votre question, mais vous pourriez envisager de passer une usine pour T comme paramètre implicite. Ceci est connu comme utilisant classes de type ou polymorphisme ad-hoc.

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] 

} 

À l'autre extrémité du spectre, vous pourriez appeler le compilateur lors de l'exécution, comme détaillé dans this answer à la question « mixin dynamique Scala - est-il possible ».

+0

Merci, je vais devoir utiliser cette méthode. Mon cas d'utilisation est le proxy Java. Je veux écrire une bibliothèque qui est à distance. J'ai donc besoin de définir des interfaces pour toutes mes classes, ce qui est une douleur car je veux tout exposer. Une solution consiste à tout écrire en tant que trait, puis j'obtiens la définition de l'interface gratuitement. Le but de la fonction create est d'instancier un trait du côté "concret" de la connexion proxy. – ACyclic

Questions connexes