在编译时强制执行 HList 类型的上限
Enforce upper bound for HList types at compile time
我正在尝试为某些类型创建通用特征 'Repo',这些类型是特征 'Identifiable' 的子类型。我的计划是通过传递描述 'Identifiable' 子类型的通用 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
我看到了这个似乎相关的问题:
Type inference on contents of shapeless HList
不同之处在于我没有要使用的 HList 的实现,所以不确定如何仅使用类型计算上限。
提供了对 HList 的一整套约束
您要找的可能是 LUBConstraint
。引用文档:
Type class witnessing that every element of L
is a subtype of 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
如果你愿意使用抽象class而不是特征,你可以让一切变得更好
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]
现在扩展 class.
时会立即出现错误
我正在尝试为某些类型创建通用特征 'Repo',这些类型是特征 'Identifiable' 的子类型。我的计划是通过传递描述 'Identifiable' 子类型的通用 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
我看到了这个似乎相关的问题: Type inference on contents of shapeless HList 不同之处在于我没有要使用的 HList 的实现,所以不确定如何仅使用类型计算上限。
您要找的可能是 LUBConstraint
。引用文档:
Type class witnessing that every element of
L
is a subtype ofB
.
要使用,您只需要 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
如果你愿意使用抽象class而不是特征,你可以让一切变得更好
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]
现在扩展 class.
时会立即出现错误