2015-07-31 9 views
14

Kann ich nicht eine generische Methode unapply eines Extraktors zusammen mit einem impliziten "Konverter" verwenden, um eine Musterübereinstimmung zu unterstützen, die für den parametrisierten Typ spezifisch ist?Kann ein Scala "Extractor" Generics auf unapply verwenden?

Ich mag würde diese (Beachten Sie die Verwendung von [T] auf der unapply Linie) zu tun,

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) 
} 

aber ich erhalte den folgenden Kompilierungsfehler

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

Es funktioniert gut, wenn ich nur einen impliziten val im Geltungsbereich habe und den Typhinweis weglasse (siehe unten), aber das das Objekt vereitelt.

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

Ich glaube nicht, dass dies im Moment möglich ist, siehe [SI-884] (https://issues.scala-lang.org/browse/SI-884). –

Antwort

2

Eine Variante Ihrer geschriebenen String Decoder sieht vielversprechend aus:

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) 
} 

dann

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" 

zu produzieren scheint, was Sie fragen. Ein Problem bleibt: Es scheint, dass der Versuch, zu

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

führt zu einem Compiler crash (zumindest in meiner 2.10.3 SBT Scala-Konsole).