【问题标题】:shapeless Mapper for LabelledGeneric not found未找到 LabelledGeneric 的无形映射器
【发布时间】:2015-07-23 21:45:43
【问题描述】:

我有这样定义的基本类型池:

sealed trait Section
final case class Header(...) extends Section
final case class Customer(...) extends Section
final case class Supplier(...) extends Section
final case class Tech(...) extends Section

我想介绍一些由这个池中的类型组成的案例类,如下所示:

final case class ContractViewPartners(customer: Customer, supplier: Supplier)
final case class ContractView(header: Header, partners: ContractViewPartners, tech: Tech)

由于它们将大量用于通过使用here 描述的方法转换为HLists 实现的特征生成器中,我想确保呈现类型的每个字段都是其中一个

  • Section 子类型
  • HListSection 子类型
  • 记录可呈现为HListSection 子类型

我已经为这种情况定义了简单的编译时检查器:

object traverseView extends Poly1 {
  implicit def caseSection[S <: Section] = at[S](_ => ())

  implicit def caseSectionList[L <: HList]
  (implicit evt: ToTraversable.Aux[L, List, Section]) = at[L](_ => ())

  implicit def caseRecord[R, L <: HList]
  (implicit lgen: LabelledGeneric.Aux[R, L],
   trav: ToTraversable.Aux[L, List, Section]) = at[R](_ => ())
}

private def contractViewIsMultiSection(v: ContractView) =  {
  val gen = LabelledGeneric[ContractView].to(v)
  gen map traverseView
}

但它失败了(删除了包名)

找不到参数映射器的隐式值: Mapper[traverseView.type,::[Header with KeyTag[Symbol with 标记为[String("header")],Header],::[ContractViewPartners with KeyTag[符号与 Tagged[String("partners")],ContractViewPartners],::[Tech with KeyTag[Symbol with Tagged[String("tech")],Tech],HNil]]]]

如果我从ContractView 中删除partners 部分,它正在工作,如果我尝试在ContractViewPartners 上解析implicits,它们也会被发现。

再次在写问题时,我找到了添加 .values 这样的解决方案

private def contractViewIsMultiSection(v: ContractView) =  {
  val gen = LabelledGeneric[ContractView].to(v)
    .values //!!!
  gen map traverseView
}

会不会是 with KeyTag[...] 类型不能作为 LabelledGeneric 转换的源正常工作?

【问题讨论】:

    标签: scala shapeless hlist labelled-generic


    【解决方案1】:

    问题是Case 是不变的,所以你有一个Case 实例ContractViewPartners 并不意味着你有一个ContractViewPartners 的case 实例带有类型级标签(它只是ContractViewPartners 的子类型)。您可以通过生成实例来非常简单地解决这个问题,例如FieldType[K, ContractViewPartners](对于一些任意的K):

    sealed trait Section
    final case class Header(s: String) extends Section
    final case class Customer(s: String) extends Section
    final case class Supplier(s: String) extends Section
    final case class Tech(s: String) extends Section
    
    final case class ContractViewPartners(customer: Customer, supplier: Supplier)
    final case class ContractView(header: Header, partners: ContractViewPartners, tech: Tech)
    
    import shapeless._, labelled.FieldType, ops.hlist.ToList
    
    object traverseView extends Poly1 {
      implicit def caseSection[S <: Section] = at[S](_ => ())
    
      implicit def caseSectionList[K, L <: HList](implicit
        lub: ToList[L, Section] 
      ) = at[FieldType[K, L]](_ => ())
    
      implicit def caseRecord[K, C, L <: HList](implicit
        gen: Generic.Aux[C, L],
        lub: ToList[L, Section] 
      ) = at[FieldType[K, C]](_ => ())
    }
    
    private def contractViewIsMultiSection(v: ContractView) =  {
      val gen = LabelledGeneric[ContractView].to(v)
      gen map traverseView
    }
    

    如果您不关心标签,也可以在 contractViewIsMultiSection 中使用 Generic[ContractView]

    不过,我可能会建议不要将Poly1 用于此类事情。如果您只是想要类型正确的证据,您可以使用自定义类型类更简洁地做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-10
      • 2014-04-14
      • 1970-01-01
      • 2019-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-02
      相关资源
      最近更新 更多