我想将 F 有界多态性转换为抽象类型成员。
trait FBoundedMovable[Self <: FBoundedMovable[Self]] {
def moveTo(pos: Vect2): Self
}
至
trait Movable { self =>
type Self <: (Movable { type Self = self.Self })
def moveTo(pos: Vect2): Self
}
到目前为止,一切都很好。
让我们定义一个实例:
case class Ship(pos: Vect2) extends Movable {
type Self = Ship
def moveTo(pos: Vect2) = copy(pos = pos)
}
并尝试使用它:
// [error] found : a.Self
// [error] required: A
def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to)
F 有界版本工作正常。
def moveF[A <: FBoundedMovable[A]](a: A, to: Vect2): A = a.moveTo(to)
我知道可以将类型边界添加到方法定义站点:
def move2[A <: Movable { type Self = A }](a: A, to: Vect2): A = a.moveTo(to)
但是是否可以在 Movable 特征声明中指定关系?如果不是 - 为什么?
编辑 1
我已经意识到我遇到了什么问题。
假设我们要声明某物是我们世界中的一个单位。
trait WorldUnit extends Movable with Damageable
所有单元都是可移动和可损坏的。
我们战斗计算的东西只关心那个东西Movable with Damagable
。它不关心它是单元还是建筑物。
但是我们可以有这样的代码:
def doCombat(obj: Movable with Damagable) = obj.moveTo(...).takeDamage(...)
def doStuffWithUnit(obj: WorldUnit): WorldUnit = doCombat(obj) // and the type is lost here.
我注定要使用 F 有界类型吗?
编辑2:
Attempting to model F-bounded polymorphism as a type member in Scala没有回答这个问题——我之前已经尝试过,它丝毫不会影响返回类型,它仍然是 a.Self。
编辑3:
我找到了http://blog.jessitron.com/2014/02/when-oo-and-fp-meet-mytype-problem.html但问题仍未解决。
基本上,每当您有收藏并想挑选一个时:
(collection: Seq[Movable]).collectFirst { m: Movable if m.someCondition => m }
- 您无法指定类型绑定,因此编译器无法证明 A#Self =:= A?