我已经阅读了几篇文章,这些文章表达了应使用抽象类型在Scala中实现f界多态性。这主要是为了减轻类型推断问题,而且还消除了在定义递归类型时类型参数似乎引入的二次增长。
这些定义如下:
trait EventSourced[E] {
self =>
type FBound <: EventSourced[E] { type FBound <: self.FBound }
def apply(event: E): FBound
}
但是,这似乎引入了两个问题:
1)每次用户想要引用此类型的对象时,他们还必须引用FBound
type参数。这感觉像代码气味:
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
}
变成:
trait Vehicle[T, W] {
val vehicleType: T
def replaceWheels(wheels: W): Vehicle[T, W]
}
这里,“预期的改变”是车辆类型(例如Bike
,Car
,Lorry
)。前面的示例假定将通过继承来添加,这需要一个f边界类型,该类型使对W
使用Vehicle的任何函数都无法进行推断。使用合成的新方法不会出现此问题。
参见:https : //github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句