从 HList 类型创建 HMap
Create HMap from HList type
给定一个 HList 类型参数,我想用 HList 类型的 typeTags 作为键创建一个 HMap,如下所示:
(不必是类型标签,只要能容纳类型即可)
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])
- 如何实现 createMap(签名,return 值和
实现)?
- 如何指定有效的 valueFunction?
我经过一番反思设法做到了这一点。可能应该将其中一些转换为宏。
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.")
})
}
给定一个 HList 类型参数,我想用 HList 类型的 typeTags 作为键创建一个 HMap,如下所示:
(不必是类型标签,只要能容纳类型即可)
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])
- 如何实现 createMap(签名,return 值和 实现)?
- 如何指定有效的 valueFunction?
我经过一番反思设法做到了这一点。可能应该将其中一些转换为宏。
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.")
})
}