F-Bounded多态与Scala中的抽象类型

时间:2013-09-01 10:25:06

标签: scala generics polymorphism scala-2.10

我已经读过几篇文章,表示应该使用抽象类型来实现Scala中的f-bounded多态。这主要是为了减轻类型推断问题,同时也消除了类型参数在定义递归类型时似乎引入的二次增长。

这些定义如下:

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-bounded多态的成功实现,编译器仍能推断出类型?

3 个答案:

答案 0 :(得分:3)

我已经意识到在大多数情况下应该避免使用f-bounded多态 - 或者更确切地说 - 这通常是你应该选择的替代设计。要了解如何避免它,我们首先需要知道是什么让我们需要它:

  

当类型期望在派生类型中引入重要接口更改时,会发生F-bounded多态。

通过编写预期的更改区域而不是尝试通过继承来支持它们,可以避免这种情况。这实际上回到了Gang of Four设计模式:

  

偏好&#39;对象组合&#39;过度继承&#39;

     

- (Gang of Four,1995)

例如:

SWIFT_VERSION

变为:

trait Vehicle[V <: Vehicle[V, W], W] {
    def replaceWheels(wheels: W): V
}

在这里,预期的变化&#39;是车型(例如trait Vehicle[T, W] { val vehicleType: T def replaceWheels(wheels: W): Vehicle[T, W] } BikeCar)。前面的示例假设这将通过继承添加,需要一个f-bounded类型,使得使用Vehicle的任何函数都无法推断Lorry。使用合成的新方法不会出现此问题。

请参阅:https://github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism

答案 1 :(得分:-1)

答案 2 :(得分:-1)

我可能会遗漏以下实施内容。

trait EventSourced[E] {
  self =>

  type FBound <: EventSourced[E] { type FBound <: self.FBound }

  def apply(event: E): FBound
}

trait Something[ES, E]

def mapToSomething[E](
  eventSourced: ES forSome {
    type ES <: EventSourced[E]
  }): Something[eventSourced.type, E] = ???

class Test extends EventSourced[Boolean] {
  type FBound = Test
  def apply(event:Boolean):FBound = ???
}

val x:Test  = ???

mapToSomething(x)