找不到LabelledGeneric的无形状映射器



我有一个基本类型池定义如下:

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

我想展示一些由这个池中的类型组成的case类,像这样:

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

由于它们将在通过使用此处描述的方法转换到HList实现的特征生成器中大量使用,因此我希望确保所呈现类型的每个字段都是

之一。
  • Section亚型
  • Section亚型HList
  • 记录显示为Section亚型的HList
我已经为这个条件定义了简单的编译时检查器:
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
}

但是使用(去掉包名)

失败

无法找到参数映射器的隐式值:(traverseView映射器。类型,::[头与KeyTag[符号与标记的字符串("头"),头],::[ContractViewPartnersKeyTag(符号与标记的字符串("伙伴"),ContractViewPartners],::[科技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转换的源吗?

问题是Case是不变的,因此您为ContractViewPartners拥有Case实例并不意味着您为ContractViewPartners拥有具有类型级别标签的案例实例(这只是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来处理这种事情。如果您只是想要证明类型是正确的,您可以使用自定义类型类来做得更干净一些。

相关内容

  • 没有找到相关文章

最新更新