给定一个HList类型参数,我想用HList类型的typeTags作为键创建一个HMap,如下所示:
(不必是typeTag,只是可以保持类型的东西)
def createMap[L <: HList](valueFunction:...):HMap = {
//create an HMap with typeTags of HList elements as keys
//values of HMap is created with passed 'valueFunction' which is a type parameterized function creating the value.
}
case class Person(..)
case class Address(..)
def valueFunction[T] = Map[Long, T]()
val hmap = createMap[Person :: Address :: HNil](valueFunction _)
val personValue:Map[Long, Person] = hmap(typeTag[Person])
答案 0 :(得分:0)
我设法通过一些反思来做到这一点。应该将其中的一部分转换为宏。
import Repository._
import shapeless.{HList, HMap, Id}
import scala.collection.mutable
import scala.reflect.api
import scala.reflect.runtime.universe._
trait Repository[L <: HList] {
implicit val ltag: TypeTag[L]
implicit object TLM extends (~??>[TypeTag, Long, mutable.Map])
val repos: HMap[(~??>[TypeTag, Long, mutable.Map])#λ] = {
val tts: List[TypeTag[_]] = ltag.tpe.dealias.typeArgs.dropRight(1).map(typeToTypeTag _)
tts.tail.foldLeft(HMap[(~??>[TypeTag, Long, mutable.Map])#λ](getEntry(tts.head)))(_ + getEntry(_))
}
}
object Repository {
def getEntry[T](key: TypeTag[T]): (TypeTag[T], mutable.Map[Long, T]) = key -> mutable.Map[Long, T]()
//copied and modified from shapeless ~?> in HMap
class ~??>[K[_], K0, V[K0, _]] extends Serializable {
class λ[K, V] extends Serializable
}
object ~??> extends NatTRel0 {
//not entirely sure if I need this method and/or the next one, but will keep it for now
implicit def rel[K[_], K0, V[K0, _]]: ~??>[K, K0, V] = new (~??>[K, K0, V])
implicit def idKeyWitness[K0, V[K0, _], T](implicit rel: ~??>[Id, K0, V]): rel.λ[T, V[K0, T]] = new rel.λ[Id[T], V[K0, T]]
//this doesnt fit 3 type params, dont know how to port from ~?>
// implicit def idValueWitness[K[_], K0, T](implicit rel: ~??>[K, K0, Id]): rel.λ[K[T], T] = new rel.λ[K[T], Id[T]]
}
trait NatTRel0 {
implicit def witness[K[_], K0, V[K0, _], T](implicit rel: ~??>[K, K0, V]): rel.λ[K[T], V[K0, T]] = new rel.λ[K[T], V[K0, T]]
}
def typeToTypeTag[T](tpe: Type)(implicit mirror: Mirror = runtimeMirror(getClass.getClassLoader)): TypeTag[T] =
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U#Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}