对于习惯于Scala类型级编程的开发人员来说,这似乎是一个经典问题,但我找不到(或者我不知道如何搜索)解决方案或模式。假设我有这样一个类:
abstract class TypedTest[Args <: HList](implicit val optMapper: Mapped[Args, Option]) {
type OptArgs = optMapper.Out
def options: OptArgs // to be implemented by subclasses
}
我希望此类的用户使用HList
类型参数(Args
)对其进行实例化,并且该类提供了一种方法来检索包含每个指定类型的实例的HList
实例在Option
(OptArgs
)内。我正在使用无形Mapped类型类。请注意,我不在实例化时提供Args
的实例。
此代码不起作用,因为编译器不会推断OptArgs
的具体类型,甚至明显正确的实现(例如def options = HNil
)也会产生编译错误。使用Aux模式的相同代码:
abstract class TypedTest[Args <: HList, OptArgs <: HList](implicit val optMapper: Mapped.Aux[Args, Option, OptArgs]) {
def options: OptArgs
}
这迫使我在实例化时指定两个列表,这使得外部API不必要地冗长。有解决方法吗?
答案 0 :(得分:0)
这是我的理解,但我并不是百分百肯定,并且很乐意接受纠正。
类型成员TypedTest.OptArgs
不是抽象类型,而是类型别名。它是TypedTest
的所有子类的相同类型 - Mapped[Args, Option].Out
的别名,它是一种抽象类型,不能与任何类型统一,只能与其本身统一。创建子类时,不会覆盖类型成员OptArgs
。
当Mapped.Aux
使用Out0
的存在类型时,它变得更加清晰,这与IIUC或多或少相同:
abstract class TypedTest[Args <: HList](
implicit val optMapper: Mapped.Aux[Args, Option, T] forSome { type T }) {
type OptArgs = optMapper.Out
def options: OptArgs // to be implemented by subclasses
}
val intTest = new TypedTest[Int :: HNil] {
def options = Some(1) :: HNil
}
Error:(18, 29) type mismatch;
found : shapeless.::[Some[Int],shapeless.HNil]
required: this.OptArgs
(which expands to) T
def options = Some(1) :: HNil
不幸的是,除了将Out
作为类型参数添加或将OptArgs
定义为抽象类型并在每个子类中明确指定它之外,我不知道任何可能的解决方案。