2

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

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)

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

  • 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 Tagged[String("header")],Header],::[ContractViewPartners with KeyTag[Symbol with Tagged[String( "partners")],ContractViewPartners],::[Tech with KeyTag[Symbol with Tagged[String("tech")],Tech],HNil]]]]

如果我从它的工作中删除partners部分ContractView并且如果我尝试解决implicits它们ContractViewPartners也会被发现。

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

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

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

4

1 回答 1

4

问题是它Case是不变的,所以你有一个Case实例的ContractViewPartners事实并不意味着你有一个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
}

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

不过,我可能会建议不要使用Poly1这种东西。如果您只想要类型正确的证据,您可以使用自定义类型类更清晰地做到这一点。

于 2015-07-24T02:43:51.060 回答