2016-11-21 1 views
2

Voici mon problème:Scala implicits et Dérogations problèmes

trait Caller { 

    type EntityType 
    def parseEntity(entity: String): EntityType 
} 

trait IntCaller extends Caller { 

    implicit def strToInt(s: String) = s.toInt 
    override type EntityType = Int 
    override def parseEntity(entity: String): EntityType = entity 
} 

trait DoubleCaller extends Caller { 

    implicit def strToDouble(s: String) = s.toDouble 
    override type EntityType = Double 
    override def parseEntity(entity: String): EntityType = entity 
}  

object main { 

    def main(args: Array[String]): Unit = { 
     val intCaller = new IntCaller{} 
     val doubleCaller = new DoubleCaller{} 

     println("Result is: " + intCaller.parseEntity("5")) 
     println("Result is: " + doubleCaller.parseEntity("5.0")) 
    } 

} 

Comme vous pouvez le voir, je ne cesse de répéter le code: méthode parseEntity. Si je voulais ajouter un FloatCaller je dois réécrire parseEntity même si sa mise en œuvre serait le même.

Comment puis-je écrire le implentation du parseEntity dans le Caller, de sorte que je ne dois pas écrire le même code dans les traits de l'enfant encore et encore?

Clause de non-responsabilité: Ceci est une simplification d'un vrai problème que j'ai avec SprayJsonSupport de akka.http.scaladsl.marshallers.sprayjson.

Répondre

4

Vous serait préférable d'utiliser une méthode de fabrication qui peut construire des instances d'un Caller donné une fonction de conversion. La seule chose qui est différente entre IntCaller et DoubleCaller est toInt et toDouble (et les types, bien sûr).

trait Caller { 
    type EntityType 
    def parseEntity(entity: String): EntityType 
} 

object Caller { 
    def apply[A](f: String => A): Caller = new Caller { 
     type EntityType = A 
     def parseEntity(entity: String): EntityType = f(entity) 
    } 
} 

scala> val IntCaller = Caller(_.toInt) 
scala> IntCaller.parseEntity("123") 
res1: IntCaller.EntityType = 123 

scala> val DoubleCaller = Caller(_.toDouble) 
scala> DoubleCaller.parseEntity("1.23") 
res2: DoubleCaller.EntityType = 1.23 

Si vous souhaitez continuer à utiliser l'héritage, puis continuer à forcer les sous-classes ou traits pour mettre en œuvre la conversion avec parseEntity. Cependant, il n'est pas vraiment nécessaire d'utiliser des conversions implicites. La seule raison pour laquelle il semble qu'il y ait du code répété est que la conversion implicite fait que parseEntity est la même pour chaque implémentation, même si ce n'est pas le cas (parce qu'elle doit résoudre un implicite différent).

trait Caller { 
    type EntityType 
    def parseEntity(entity: String): EntityType 
} 

trait IntCaller { 
    type EntityType = Int 
    def parseEntity(entity: String): EntityType = entity.toInt 
}