从HList类型创建HMap

时间:2016-07-04 08:45:11

标签: scala shapeless

给定一个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])
  1. 如何实现createMap(签名,返回值和 implementaion)吗
  2. 如何指定有效的valueFunction?

1 个答案:

答案 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.")
        })
    }