【发布时间】:2012-09-13 17:08:25
【问题描述】:
我从 Landei here 借用了 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 方法中的下划线最终会为a.SELF 生成一个Any。但是我怎样才能使这段代码工作呢?
我也试过这个:
def spitAt[A <: SpittableAnimal[A]](a: A): A = a.withMoreAnger
但是推断的类型参数不符合方法 spitAt 的类型参数边界,这对我来说很清楚,因为 animals 中元素的 SELF 类型参数至少由不符合的 _ >: Cat with Dog <: Quadruped[_] 限定a.SELF, A 在上面的spitAt 甚至A 在下面的spitAt:
def spitAt[A <: SpittableAnimal[S], S <: A](a: A): A = a.withMoreAnger
那么,使for-loop 行工作的spitAt 方法的正确签名是什么?
也许 SELF 类型参数的方差注释 (+SELF) 可能会有所帮助,但我不知道如何。
【问题讨论】: