2015-07-31 1 views
14

Impossible d'utiliser un générique sur la méthode unapply d'un extracteur avec un "convertisseur" implicite pour prendre en charge une correspondance de modèle spécifique au type paramétré?Un «extracteur» Scala peut-il utiliser des génériques en cas d'inapplication?

Je voudrais faire (Notez l'utilisation de [T] sur la ligne unapply),

trait StringDecoder[A] { 
    def fromString(string: String): Option[A] 
} 

object ExampleExtractor { 
    def unapply[T](a: String)(implicit evidence: StringDecoder[T]): Option[T] = { 
    evidence.fromString(a) 
    } 
}  

object Example extends App {   

implicit val stringDecoder = new StringDecoder[String] { 
    def fromString(string: String): Option[String] = Some(string) 
    } 

    implicit val intDecoder = new StringDecoder[Int] { 
    def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt) 
    } 

    val result = "hello" match { 
    case ExampleExtractor[String](x) => x  // <- type hint barfs 
    } 
    println(result) 
} 

Mais je reçois l'erreur compilation suivante

Error: (25, 10) not found: type ExampleExtractor case ExampleExtractor[String] (x) => x ^

Cela fonctionne très bien si je n'ai qu'une seule val implicite dans la portée et que je supprime l'indice de type (voir ci-dessous), mais cela détruit l'objet.

object Example extends App { 

    implicit val intDecoder = new StringDecoder[Int] { 
    def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt) 
    } 

    val result = "hello" match { 
    case ExampleExtractor(x) => x 
    } 
    println(result) 
} 
+2

Je ne pense pas que ce soit possible pour le moment, voir [SI-884] (https://issues.scala-lang.org/browse/SI-884). –

Répondre

2

Une variante de votre décodeur de chaîne typé semble prometteur:

trait StringDecoder[A] { 
    def fromString(s: String): Option[A] 
} 

class ExampleExtractor[T](ev: StringDecoder[T]) { 
    def unapply(s: String) = ev.fromString(s) 
} 
object ExampleExtractor { 
    def apply[A](implicit ev: StringDecoder[A]) = new ExampleExtractor(ev) 
} 

puis

implicit val intDecoder = new StringDecoder[Int] { 
    def fromString(s: String) = scala.util.Try { 
     Integer.parseInt(s) 
    }.toOption 
} 

val asInt = ExampleExtractor[Int] 
val asInt(Nb) = "1111" 

semble produire ce que vous demandez. Un problème demeure: dans un accident du compilateur, il semble que d'essayer de

val ExampleExtractor[Int](nB) = "1111" 

résultats (au moins à l'intérieur de mon 2.10.3 console SBT Scala).