2016-07-25 1 views
2

J'ai un trait qui est générique et va comme ceci:Scala instancier une classe de béton De type générique

trait MyTrait[T] { 
    def doSomething(elems: Seq[T]) 
} 

Je puis une usine d'objet dont la définition va comme ceci:

object MyTraitFactory { 
    def apply[T](param1: Boolean, param2: Boolean): MyTrait[T] = { 
    // based on the type of T, I would like to instantiate sub types 
    } 
} 

I sont venus des implémentations concrètes qui sont par exemple:

class MyStringTrait extends MyTrait[String] 

class MyIntTrait extends MyTrait[Int] 

J'ai maintenant besoin de ce bit magique qui chercherait le tapez dans ma fabrique d'objets et instanciez les implémentations correspondantes. Aucune suggestion?

Répondre

3

Cela peut être résolu dans scala en utilisant une classe de type implicite. Créer un trait d'usine avec des implémentations concrètes pour chacun de vos types:

object MyTraitFactory { 

    def apply[T](param1: Boolean, param2: Boolean)(implicit factory: MyTraitCreator[T]): MyTrait[T] = { 
    // call the typeclass create method 
    factory.create(param1, param2) 
    } 

    // factory trait 
    trait MyTraitCreator[T] { 
    def create(param1: Boolean, param2: Boolean): MyTrait[T] 
    } 

    // provide an implicit factory object for the specific types: 
    object MyTraitCreator { 

    implicit object MyStringTraitCreator extends MyTraitCreator[String] { 
     override def create(param1: Boolean, param2: Boolean): MyTrait[String] = { 
     // create the String type here 
     new MyStringTrait 
     } 
    } 

    implicit object MyIntTraitCreator extends MyTraitCreator[Int] { 
     override def create(param1: Boolean, param2: Boolean): MyTrait[Int] = { 
     // create the Int type here 
     new MyIntTrait 
     } 
    } 
    } 
} 

Scala « cache » l'aide du paramètre classe de types implicite. Mais pour que cela fonctionne, vous devez vous assurer de conserver les objets usine implicites quelque part où le compilateur recherche des implicits (par exemple, l'objet compagnon à MyTraitCreator comme ci-dessus). Le modèle fonctionne aussi bien sans le implicit, mais nécessite ensuite l'appelant pour fournir l'usine de béton à chaque appel.

Cette solution comprend beaucoup de code de plaque de chaudière mais fonctionne statiquement au moment de la compilation et ne souffre pas d'effacement de type. Il vient même avec du sucre syntaxique en scala:

def apply[T: MyTraitCreator](param1: Boolean, param2: Boolean): MyTrait[T] = { 
    // call the typeclass create method 
    implicitly[MyTraitCreator[T]].factory.create(param1, param2) 
}