我试图创建一个通用的特质' Repo'对于某些类型是特征的子类型,可以识别'。我的计划是实例化Repo'的实现者。通过传递描述' Identifiable' -subtypes的通用TypeTag [HList]。
如何让编译器保证在HList中传递的类型是特征的子类型'可识别'?
这是我到目前为止所得到的:
//All types in HList must extend Identifiable, how to enforce that at compile time?
trait Repo {
implicit val ltag: TypeTag[L] forSome {type L <: HList}
..
}
trait Identifiable {
..
}
case class Person(..) extends Identifiable
case class Address(..)
//This should compile
class MyRepo
(implicit val ltag: TypeTag[Person :: HNil])
extends Repo {
..
}
//This should not
class MyRepo
(implicit val ltag: TypeTag[Address :: HNil])
extends Repo {
..
}
//HList can contain an unknown number of types
我已经看到这个似乎有关的问题: Type inference on contents of shapeless HList 区别在于我没有使用HList的实现,因此不确定如何仅使用类型计算上限。
答案 0 :(得分:3)
由https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/hlistconstraints.scala提供的HList有一整套约束。
你所追求的人可能是LUBConstraint
。引用文档:
键入类,见证
L
的每个元素都是B
的子类型。
要使用,您只需要隐含LUBContraint[L, Identifiable]
的证据。
E.g。
trait Repo[L <: HList] {
implicit val ltag: TypeTag[L]
implicit val ev: LUBConstraint[L, Identifiable]
}
trait Identifiable
case class Person(name: String) extends Identifiable
case class Address(street: String)
type P = Person :: HNil
class MyPersonRepo(implicit
val ltag: TypeTag[P],
val ev: LUBConstraint[P, Identifiable]
) extends Repo[P]
type A = Address :: HNil
class MyAddressRepo(implicit
val ltag: TypeTag[A],
val ev: LUBConstraint[A, Identifiable]
) extends Repo[A]
new MyPersonRepo // this works
new MyAddressRepo // this doesn't
如果你愿意使用抽象类而不是特质,你可以使一切更好
abstract class Repo[L <: HList](implicit
val ltag: TypeTag[L],
val ev: LUBConstraint[L, Identifiable]
)
trait Identifiable
case class Person(name: String) extends Identifiable
case class Address(street: String)
type P = Person :: HNil
class MyPersonRepo extends Repo[P]
type A = Address :: HNil
class MyAddressRepo extends Repo[A]
现在,在扩展课程时,您将立即收到错误。