我的基本类型池定义如下:
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描述的方法透射到HList
实现的特征生成器,我希望确保呈现类型的每个字段都是< / p>
Section
子类型HList
Section
个子类型
HList
子类型的Section
我已为此条件定义了简单的编译时检查程序:
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,:: [带KeyTag的标题] [带符号的符号] Tagged [String(&#34; header&#34;)],Header],:: [ContractViewPartners with KeyTag [符号与 Tagged [String(&#34; partners&#34;)],ContractViewPartners],:: [Tech with KeyTag [带有标记的符号[String(&#34; tech&#34;)],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
转换的来源吗?
答案 0 :(得分:3)
问题是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]
中使用contractViewIsMultiSection
。
但我建议不要使用Poly1
来做这类事情。如果您只是想要证明类型是正确的,那么您可以使用自定义类型更干净一些。