我读过几篇文章,表达了应该使用抽象类型来实现 Scala 中的 f 有界多态性。这主要是为了缓解类型推断问题,同时也是为了消除定义递归类型时类型参数似乎引入的二次增长。
这些定义如下:
trait EventSourced[E] {
self =>
type FBound <: EventSourced[E] { type FBound <: self.FBound }
def apply(event: E): FBound
}
然而,这似乎引入了两个问题:
1) 每次用户想要引用该类型的对象时,他们还必须引用FBound
类型参数。这感觉就像代码味道:
def mapToSomething[ES <: EventSourced[E], E](eventSourced: ES#FBound): Something[ES, E] = ...
2) 编译器现在无法推断上述方法的类型参数,失败并显示消息:
Type mismatch, expected: NotInferredES#FBound, actual: MyImpl#FBound
是否有人在其解决方案中成功实现了 f 有界多态性,从而编译器仍然能够推断类型?
从那时起,我意识到在大多数情况下应该避免 f 有界多态性 - 或者更确切地说 - 通常您应该选择另一种设计。要了解如何避免它,我们首先需要知道是什么让我们需要它:
当类型期望时,就会发生 F 有界多态性重要的界面变化在派生类型中引入。
这是通过以下方式避免的构成预期的变化领域,而不是试图通过继承来支持它们。这实际上又回到了四人帮设计模式:
优先选择“对象组合”而不是“类继承”
——(四人帮,1995)
例如:
trait Vehicle[V <: Vehicle[V, W], W] {
def replaceWheels(wheels: W): V
}
becomes:
trait Vehicle[T, W] {
val vehicleType: T
def replaceWheels(wheels: W): Vehicle[T, W]
}
这里,“预期变化”是车辆类型(例如Bike
, Car
, Lorry
)。前面的示例假设这将通过继承添加,需要一个 f-bounded 类型来推断W
使用车辆不可能实现任何功能。使用组合的新方法不会出现这个问题。
See: https://github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism https://github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)