我在这里借用了Landei 的 MyType 技巧。但是最近我遇到了 self 类型的问题。一个例子说明了我的意思:
trait Excitable[SELF] { self: SELF =>
def withMoreAnger: SELF
}
trait Animal[SELF0] { self: SELF0 =>
type SELF = SELF0 // to reveal SELF0 for method spitAt used as a dependent method type
type SpittableAnimal[S] <: Animal[S]
def spitAt[A <: SpittableAnimal[_]](a: A): a.SELF
}
trait ExcitableAnimal[SELF] extends Animal[SELF] with Excitable[SELF] { self: SELF =>
type SpittableAnimal[S] = ExcitableAnimal[S]
def spitAt[A <: SpittableAnimal[_]](a: A): a.SELF = a.withMoreAnger
}
trait Quadruped[SELF] extends ExcitableAnimal[SELF] { self: SELF => }
case class Dog(anger: Int) extends Quadruped[Dog] {
def withMoreAnger: Dog = copy(anger = anger + 1)
}
case class Cat(anger: Int) extends Quadruped[Cat] {
def withMoreAnger: Cat = copy(anger = anger + 1)
}
val dog = Dog(anger = 0)
val cat = Cat(anger = 0)
val angryCat: Cat = dog spitAt cat // fine
val anotherDog = Dog(0)
val animals = Seq(dog, cat)
val angryAnimals: Seq[Quadruped[_]] = for (a <- animals) yield anotherDog spitAt a // fine
val veryAngryAnimals: Seq[Quadruped[_]] = for (a <- angryAnimals) yield anotherDog spitAt a // type mismatch !!!
据我所知,问题似乎是该spitAt
方法中的下划线最终会产生一个Any
for a.SELF
。但是我怎样才能使这段代码工作呢?
我也试过这个:
def spitAt[A <: SpittableAnimal[A]](a: A): A = a.withMoreAnger
但是推断的类型参数不符合方法 spitAt 的类型参数边界,这对我来说很清楚,因为SELF
元素的类型参数animals
至少有边界_ >: Cat with Dog <: Quadruped[_]
不符合a.SELF
,A
在spitAt
上面甚至A
在spitAt
下面:
def spitAt[A <: SpittableAnimal[S], S <: A](a: A): A = a.withMoreAnger
那么spitAt
使for
-loop 行工作的方法的正确签名是什么?
也许 SELF 类型参数的方差注释 ( +SELF
) 可能会有所帮助,但我不知道如何。