如何匹配泛型类型中包含的类型变量?

时间:2016-06-04 20:45:18

标签: scala reflection pattern-matching

我正在编写一个Scala子例程来构造一个TypeTag [Map [_&lt ;: A,_<:B]]来自2个类型标签:

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

上限是必要的,因为A和B都被声明为协变,但TypeTag [T]是不变的。

我尝试使用大小写匹配来获取A和B的隐式类型变量,但发现Scala中的类型模式匹配相对一周。也就是说,下面的代码无法编译:

(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]]
}

因为t1和t2无法解析。我该怎么做才能解决这个问题呢?

1 个答案:

答案 0 :(得分:0)

这减少了从TypeTag[t1]获得TypeTag[Iterable[t1]]。这是可能的,但非常难看:https://stackoverflow.com/a/25691045/9204

所以你最终会得到类似的东西(未经测试!):

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