2016-06-04 9 views
1

Ich bin ein Scala-Unterprogramm das Schreiben eines TypeTag zu konstruieren [Map [_ <: A, _ <: B]] von 2 typetags:Wie wird die Groß-/Kleinschreibung einer Typvariablen in einem generischen Typ angepasst?

tag1: TypeTag[Iterable[_<: A]] 
tag2: TypeTag[Iterable[_<: B]] 

Die Oberegrenze ist notwendig, da sowohl A als auch B als deklariert werden kovariant, aber TypeTag [T] ist invariant.

Ich versuche, Case-Match zu verwenden, um implizite Typ Variablen von A und B zu erhalten, aber fand, dass Muster Übereinstimmung in Scala ist relativ Woche. Der folgende Code kann nämlich nicht kompiliert werden:

(tag1, tag2) match { 
    case (tt1: TypeTag[Iterable[t1]], tt2: TypeTag[Iterable[t2]]) => 
    implicit val t1 = tt1 
    implicit val t2 = tt2 
    ScalaReflection.universe.typeTag[Map[t1, t2]] 
} 

weil t1 und t2 nicht aufgelöst werden können. Was soll ich tun, um das Problem zu umgehen?

Antwort

0

Dies reduziert sich auf einen TypeTag[t1] von einem TypeTag[Iterable[t1]]. Was möglich ist, aber ziemlich hässlich: https://stackoverflow.com/a/25691045/9204.

So beenden Sie mit so etwas wie oben (ungetestet!):

import scala.reflect.runtime.universe._ 

def typeToTypeTag[T](
    tpe: Type, 
    mirror: reflect.api.Mirror[reflect.runtime.universe.type] 
): TypeTag[T] = { 
    TypeTag(mirror, new reflect.api.TypeCreator { 
    def apply[U <: reflect.api.Universe with Singleton](m: reflect.api.Mirror[U]) = { 
     assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.") 
     tpe.asInstanceOf[U#Type] 
    } 
    }) 
} 

def argTypeTag[A](tag: TypeTag[_ /* Actually F[A] for some F */]): TypeTag[A] = 
    typeToTypeTag[A](tag.tpe.typeArgs.head) 

(tag1, tag2) match { 
    case (tt1: TypeTag[Iterable[t1]], tt2: TypeTag[Iterable[t2]]) => 
    implicit val t1 = argTypeTag[t1](tt1) 
    implicit val t2 = argTypeTag[t2](tt2) 
    typeTag[Map[t1, t2]] 
}