在编译时强制HList类型的上限



我试图为一些类型创建一个通用的特征'Repo',这些类型是特征'可识别'的子类型。我的计划是通过传递一个描述'可识别'子类型的泛型TypeTag[HList]来实例化'Repo'的实现者。

我如何使编译器保证在HList中传递的类型是trait 'Identifiable'的子类型?

这是我到目前为止得到的:

    //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

我看到这个问题似乎是相关的:对非形状HList的内容进行类型推断不同之处在于,我没有HList的实现,所以我不确定如何计算只有类型的上限。

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/hlistconstraints.scala提供了一整套HList约束。

你要找的可能是LUBConstraint。引用文档:

类型类见证L的每个元素都是B的子类型。

要使用

,您只需要要求LUBContraint[L, Identifiable]的隐式证据。

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

如果你愿意使用抽象类而不是trait,你可以让一切变得更好

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]

现在,当您扩展该类时,您将立即得到错误。

最新更新