代码之家  ›  专栏  ›  技术社区  ›  samthebest Ende Neu

为什么这个将映射字符串转换为any-to-case类的无形状代码没有编译?

  •  1
  • samthebest Ende Neu  · 技术社区  · 6 年前

    我试着按照这里的答案 https://stackoverflow.com/a/31641779/1586965

    也就是说,我希望能够转换(可能是嵌套的) Map[String, Any] 去上案例课。

    scalaVersion := "2.11.8"
    val shapelessV = "2.3.3"
    

    如果我试图将上述答案中的代码包装到另一个泛型函数中,我似乎无法编译它

    import shapeless._, labelled._
    import FromMap._
    
    def usesGenerics[P](map: Map[String, Any]): P = {
      to[P].from(mp).get
    }
    

    我得到以下编译错误

    could not find implicit value for parameter gen: shapeless.LabelledGeneric.Aux[P,R]
    

    完整答案

    这包含了travis的最初想法和dmytros修正,最后是一些简化

    import shapeless._, labelled.{FieldType, field}
    
    trait FromMap[L <: HList] {
      def apply(m: Map[String, Any]): Option[L]
    }
    
    trait LowPriorityFromMap {
      implicit def hconsFromMap1[K <: Symbol, V, T <: HList](implicit
                                                             witness: Witness.Aux[K],
                                                             typeable: Typeable[V],
                                                             fromMapT: Lazy[FromMap[T]]
                                                            ): FromMap[FieldType[K, V] :: T] = new FromMap[FieldType[K, V] :: T] {
        def apply(m: Map[String, Any]): Option[FieldType[K, V] :: T] = for {
          v <- m.get(witness.value.name)
          h <- typeable.cast(v)
          t <- fromMapT.value(m)
        } yield field[K](h) :: t
      }
    }
    
    object FromMap extends LowPriorityFromMap {
      implicit val hnilFromMap: FromMap[HNil] = new FromMap[HNil] {
        def apply(m: Map[String, Any]): Option[HNil] = Some(HNil)
      }
    
      implicit def hconsFromMap0[K <: Symbol, V, R <: HList, T <: HList](implicit
                                                                         witness: Witness.Aux[K],
                                                                         gen: LabelledGeneric.Aux[V, R],
                                                                         fromMapH: FromMap[R],
                                                                         fromMapT: FromMap[T]
                                                                        ): FromMap[FieldType[K, V] :: T] =
        new FromMap[FieldType[K, V] :: T] {
          def apply(m: Map[String, Any]): Option[FieldType[K, V] :: T] = for {
            v <- m.get(witness.value.name)
            r <- Typeable[Map[String, Any]].cast(v)
            h <- fromMapH(r)
            t <- fromMapT(m)
          } yield field[K](gen.from(h)) :: t
        }
    }
    
    trait CaseClassFromMap[P <: Product] {
      def apply(m: Map[String, Any]): Option[P]
    }
    
    object CaseClassFromMap {
      implicit def mk[P <: Product, R <: HList](implicit gen: LabelledGeneric.Aux[P, R],
                                                fromMap: FromMap[R]): CaseClassFromMap[P] = new CaseClassFromMap[P] {
        def apply(m: Map[String, Any]): Option[P] = fromMap(m).map(gen.from)
      }
    
      def apply[P <: Product](map: Map[String, Any])(implicit fromMap: CaseClassFromMap[P]): P = fromMap(map).get
    }
    
    0 回复  |  直到 6 年前
        1
  •  1
  •   samthebest Ende Neu    6 年前

    这对你有用吗?

    def usesGenerics[P, R <: HList](map: Map[String, Any])(implicit gen: LabelledGeneric.Aux[P, R], fromMap: FromMap[R]): P = {
      to[P].from[R](map).get
    }
    

    你还需要一个类型类

      trait CaseClassFromMap[P <: Product] {
        def apply(m: Map[String, Any]): Option[P]
      }
      object CaseClassFromMap {
        implicit def mk[P <: Product, R <: HList](implicit
          gen: LabelledGeneric.Aux[P, R],
          fromMap: FromMap[R]
          ): CaseClassFromMap[P] = new CaseClassFromMap[P] {
          def apply(m: Map[String, Any]): Option[P] = to[P].from[R](m)
        }
      }
    
      def usesGenerics[P <: Product](map: Map[String, Any])(implicit fromMap: CaseClassFromMap[P]): P = {
        fromMap(map).get
      }
    
      usesGenerics[Person](mp)
    
    推荐文章