Scala泛型在抽象函数中

时间:2015-02-19 19:20:48

标签: scala generics inheritance

有一个抽象类AnimalAnimal扩展为DogCowAnimal有一个抽象函数copy。在Dog上被调用时,应该返回Dog并在Cow - Cow上调用。

abstract class Animal[T] {
  def copy[CT <: Animal[T]] (): CT
}

class Dog[T] extends Animal[T] {
  def copy = new Dog[T]()
}

这会出错。我做错了什么?

2 个答案:

答案 0 :(得分:2)

copy中的Dog方法与copyAnimal方法的签名不同(Animal有一个类型参数{{1}因为Scala编译器认为你没有为Dog实现它。看起来你正试图解决Dog应返回子类型的事实。您可以使用自我类型:

copy

除非你对type参数有其他想法吗?

在这种情况下使用F-bounded多态可能更为谨慎,以验证abstract class Animal[T] { self: T => def copy: T = this } class Dog extends Animal[Dog] T的子类型。

Animal

答案 1 :(得分:1)

基本上CT必须对您的工作方法不变。您对Dog的具体实现无法控制CT的类型,例如,使用您的方法无法解释此问题(因此编译器错误):

new Dog[Int]().copy[Cow[Int]]()

你的具体实现给了我一个Dog,但我想要一个Cow。这是因为您的copy方法不可能满足返回类型参数方差。如果您需要的只是copy方法的一种返回类型,您可以使用此替代方案(受到与C ++中相同的问题的启发):

abstract class Animal[T, SubType <: Animal[T, _]] {
  def copy (): SubType
}

class Dog[T] extends Animal[T, Dog[T]] {
  override def copy() = new Dog[T]
}

val animal: Animal[Int, Dog[Int]] = new Dog()
val dogCopy: Dog[Int] = animal.copy()

这是另一种更简单(不那么明显)的方法。 Scala允许您不仅覆盖方法的实现,还覆盖某种程度的返回类型:

abstract class Animal[T] {
  def copy (): Animal[T]
}

class Dog[T] extends Animal[T] {
  override def copy() = new Dog[T]
}

val dog = new Dog[Int]()
val dogCopy: Dog[Int] = dog.copy()