Law*_*eld 5 generics polymorphism scala scala-2.10
我已经阅读了几篇文章,表示应该使用抽象类型来实现Scala中的f-bounded多态.这主要是为了缓解类型推断问题,同时也消除了类型参数在定义递归类型时似乎引入的二次增长.
这些定义如下:
trait EventSourced[E] {
self =>
type FBound <: EventSourced[E] { type FBound <: self.FBound }
def apply(event: E): FBound
}
Run Code Online (Sandbox Code Playgroud)
但是,这似乎引入了两个问题:
1)每次用户想要引用此类型的对象时,他们还必须引用FBound
类型参数.这感觉就像代码味道:
def mapToSomething[ES <: EventSourced[E], E](eventSourced: ES#FBound): Something[ES, E] = ...
Run Code Online (Sandbox Code Playgroud)
2)编译器现在无法推断上述方法的类型参数,但没有消息:
Type mismatch, expected: NotInferredES#FBound, actual: MyImpl#FBound
Run Code Online (Sandbox Code Playgroud)
是否有人在其解决方案中使用f-bounded多态的成功实现,编译器仍然可以推断类型?
从那时起,我意识到在大多数情况下应该避免 f 有界多态性 - 或者更确切地说 - 通常您应该选择另一种设计。要了解如何避免它,我们首先需要知道是什么让我们需要它:
当类型期望在派生类型中引入重要的接口更改时,就会发生 F 界多态性。
通过组合预期的变更区域而不是尝试通过继承来支持它们,可以避免这种情况。这实际上又回到了四人帮设计模式:
优先考虑“对象组合”而不是“类继承”
——(四人帮,1995)
例如:
trait Vehicle[V <: Vehicle[V, W], W] {
def replaceWheels(wheels: W): V
}
Run Code Online (Sandbox Code Playgroud)
变成:
trait Vehicle[T, W] {
val vehicleType: T
def replaceWheels(wheels: W): Vehicle[T, W]
}
Run Code Online (Sandbox Code Playgroud)
这里,“预期变化”是车辆类型(例如Bike
、Car
、Lorry
)。前面的示例假设这将通过继承添加,需要一个 f 边界类型,这使得W
使用 Vehicle 的任何函数都无法进行推断。使用组合的新方法不会出现这个问题。
请参阅: https: //github.com/ljwagerfield/scala-type-in ference/blob/master/README.md#avoiding-f-bounded-polymorphism
归档时间: |
|
查看次数: |
1450 次 |
最近记录: |