抽象函数中的 Scala 泛型

Scala generics in an abstract function

有摘要classAnimalAnimalDogCow 扩展。 Animal 有一个抽象函数 copy。在 Dog 上调用时应该 return Dog 并且在 Cow 上调用时 - Cow.

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

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

这给出了一个错误。我做错了什么?

您在 Dog 中的 copy 方法与 Animal 中的 copy 方法没有相同的签名(Animal 有一个类型参数和 Dog 没有),因此 Scala 编译器认为您没有为 Dog 实现它。看起来您正在尝试解决 copy 应该 return 子类型的事实。您可以为此使用自我类型:

abstract class Animal[T] { self: T =>
  def copy: T = this
}

class Dog extends Animal[Dog]

除非您对类型参数有其他想法?

在这种情况下使用 F-bounded 多态性可能更谨慎,以验证 TAnimal.

的子类型
abstract class Animal[T <: Animal[T]]

本质上 CT 对于您的工作方法必须是不变的。 Dog 的具体实现无法控制 CT 的类型,例如,您的方法无法解释这一点(因此出现编译器错误):

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

你的具体实现给了我 Dog 但我想要 Cow。这是因为您的 copy 方法不可能满足 return 类型参数方差。如果你只需要一个 return 类型用于 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 不仅允许您覆盖方法的实现,还允许您在某种程度上覆盖 return 类型:

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()