art*_*raz 6 scala abstract-type parametric-polymorphism f-bounded-polymorphism
我想将F有界多态转换为抽象类型成员.
trait FBoundedMovable[Self <: FBoundedMovable[Self]] {
def moveTo(pos: Vect2): Self
}
Run Code Online (Sandbox Code Playgroud)
至
trait Movable { self =>
type Self <: (Movable { type Self = self.Self })
def moveTo(pos: Vect2): Self
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.
让我们定义一个实例:
case class Ship(pos: Vect2) extends Movable {
type Self = Ship
def moveTo(pos: Vect2) = copy(pos = pos)
}
Run Code Online (Sandbox Code Playgroud)
并尝试使用它:
// [error] found : a.Self
// [error] required: A
def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to)
Run Code Online (Sandbox Code Playgroud)
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 trait声明中指定关系吗?如果没有 - 为什么?
我意识到我遇到了什么问题.
让我们说我们想宣布某事是我们世界的一个单位.
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.
Run Code Online (Sandbox Code Playgroud)
我注定了F有界类型吗?
尝试将F-bounded多态性建模为Scala中的类型成员没有回答这个问题- 我之前尝试过这种方法并且它不会影响返回类型,它仍然是一个自我.
我找到了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?
scala中的类型投影是路径相关的。快速示例
scala> trait A{
| type T
| }
defined trait A
scala> val a = new A{type T = String}
a: A{type T = String} = $anon$1@31198ceb
scala> val b = new A{type T = String}
b: A{type T = String} = $anon$1@236ab296
scala> def f(implicit evidence: A =:= b.T) = null
f: (implicit evidence: =:=[A,b.T])Null
scala> f("asdf":a.T)
<console>:12: error: type mismatch;
found : a.T
(which expands to) String
required: =:=[A,b.T]
(which expands to) =:=[A,String]
f("asdf":a.T)
^
Run Code Online (Sandbox Code Playgroud)
在您的情况下,它会因返回类型而引发错误。它正确地期望a.type但你返回A。而且它们并不相同。
它们不应该相同的原因是:
a.type返回一个类型<: Movable。对于想象,某个x小于 100 的数字。方法move返回A,对于想象,它是另一个y小于 100 的数字。x 不必与 y 相同。