【发布时间】:2018-02-26 20:58:58
【问题描述】:
在这个假设中,我有一个要执行的操作列表。如果可以将列表中的某些操作批处理在一起(例如,从数据库中的同一个表中查找不同的行),则该列表中的某些操作将更有效。
trait Result
trait BatchableOp[T <: BatchableOp[T]] {
def resolve(batch: Vector[T]): Vector[Result]
}
这里我们使用F-bounded Polymorphism,让操作的实现可以引用自己的类型,非常方便。
但是,这在执行时会带来问题:
def execute(operations: Vector[BatchableOp[_]]): Vector[Result] = {
def helper[T <: BatchableOp[T]](clazz: Class[T], batch: Vector[T]): Vector[Result] =
batch.head.resolve(batch)
operations
.groupBy(_.getClass)
.toVector
.flatMap { case (clazz, batch) => helper(clazz, batch)}
}
这会导致编译器错误指出inferred type arguments [BatchableOp[_]] do not conform to method helper's type parameter bounds [T <: BatchableOp[T]]。
如何让 Scala 编译器确信 group 是同一类型(BatchableOp 的子类)?
- 一种解决方法是specify the type explicitly,但在这种情况下类型未知。
- 另一种解决方法依赖于enumerating the child types,但我希望在实现新的
BatchableOp类型后不必更新execute方法。
【问题讨论】:
-
对不起,我不得不放弃。 scala 中的 f-bound + 破碎的存在类型很难驯服。
-
@HuStmpHrrr 为什么“坏了”?您是否至少设法使编译器崩溃,或者您只是不喜欢存在主义? ;) 存在主义主要是“破碎”for the higher kinds,但我无法让它在这个问题上崩溃:]
-
@AndreyTyukin 从这个意义上说并没有坏掉。首先,存在类型优于协变/反变类型是多余的。在不变的情况下,类型参数上的存在类型非常无用,因为缺乏安全恢复信息类型的方法;但是,编写私有类型变量确实更有意义。如您的答案所示,它在语法上也被破坏了。我个人不喜欢存在类型,因为我早期使用它的经验很糟糕,我意识到每当我想使用它时,我并不真的需要它。
-
当您编写一个完全通用的框架时,它们在极少数情况下很有用,并且在某些时候必须将类型化的高级构造分解成一堆不同类型的小块,然后压扁进入某种较低级别调度程序的队列。由于 OP 在这里批处理作业,因此存在主义的出现似乎是适当的,甚至是不可避免的。但是,是的,在应用程序的不那么低级别的部分中,您并不经常需要它们。
标签: scala