使用shapless将HList转换为Map

时间:2016-04-09 20:38:54

标签: shapeless

我开始使用无形状,作为概念证明,我定义了将Hlist转换为Map的功能,但是出了点问题,你能帮帮我吗?

object bar extends Poly1 {
   implicit def caseTuple[T, U](implicit st: Case.Aux[T, Map[String, Any]], su: Case.Aux[U, Map[String, Any]]) =
  at[(T, U)](t => {
    Map(s"${t._1}" -> t._2)
  })
}

object foo extends Poly2 {
implicit def default[T](implicit st: bar.Case.Aux[T, Map[String, Any]]) =
  at[Map[String, Any], T] { (acc, t) =>
    acc ++ bar(t)
  }
}

val h = ("k1", 1) :: ("k2", "foo") :: HNil
println(h.foldLeft(Map.empty[String, Any])(foo)) 

但是我收到了错误:could not find implicit value for parameter folder: shapeless.ops.hlist.LeftFolder[shapeless.::[(String, Int),shapeless.::[(String, String),shapeless.HNil]],scala.collection.immutable.Map[String,Any],Main.foo.type] [error] println(h.foldLeft(Map.empty[String, Any])(foo))

1 个答案:

答案 0 :(得分:1)

  1. 由于您不关心值类型,因此您不需要为值类型提供专用的多态函数。

  2. 如果您只是依赖.toString,则不需要Poly1,以便上述示例可以像这样重写:

    < / LI>
    object foo1 extends Poly2 {
      implicit def default[K, V] =
        at[Map[String, Any], (K, V)] { case (acc, (k, v)) =>
          acc + (k.toString -> v)
        }
    }
    
    val h = ("k1", 1) :: ("k2", "foo") :: (true, "TRUE") :: HNil
    println(h.foldLeft(Map.empty[String, Any])(foo1))
    // Map(k1 -> 1, k2 -> foo, true -> TRUE)
    
    1. 如果键位置有多种类型,则需要将它们转换为字符串。它可以是Poly1或提供scalaz.Show的任何类别类,例如cats.ShowA => String
    2. object bar2 extends Poly1 {
        implicit val stringCase = at[String](identity)
        implicit val symbolCase = at[Symbol](_.name)
        implicit def integralCase[A: Integral] = at[A](_.toString)
        implicit def fractionalCase[A: Fractional] = at[A](_ formatted "%.2f")
      }
      
      object foo2 extends Poly2 {
        implicit def default[K, V](implicit bk: bar2.Case.Aux[K, String]) =
          at[Map[String, Any], (K, V)] { case (acc, (k, v)) =>
            acc + (bk(k) -> v)
          }
      }
      
      val h2 = ("k1", 1) :: ("k2", "foo") :: ('k3, true) :: (12.3456, 'frac) :: HNil
      println(h2.foldLeft(Map.empty[String, Any])(foo2))
      // Map(k1 -> 1, k2 -> foo, k3 -> true, 12.35 -> 'frac)
      

      您也可以使用其他密钥类型代替Any