How to case match a type variable enclosed in a generic type?

微笑、不失礼 提交于 2019-12-13 01:04:42

问题


I'm writing a Scala subroutine to construct a TypeTag[Map[_<: A, _<: B]] from 2 typetags:

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

The upperbound is necessary because both A and B are declared as covariant, yet TypeTag[T] is invariant.

I'm trying to use case match to get implicit type variables of A and B, but found that type pattern match in Scala is relatively week. Namely, the folloing code fails to be compiled:

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

because t1 and t2 cannot be resolved. What should I do to fix-circumvent this?


回答1:


This reduces to getting a TypeTag[t1] from a TypeTag[Iterable[t1]]. Which is possible, but quite ugly: https://stackoverflow.com/a/25691045/9204.

So you end up with something like (untested!):

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


来源:https://stackoverflow.com/questions/37634849/how-to-case-match-a-type-variable-enclosed-in-a-generic-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!