有一个抽象类Animal
。
Animal
扩展为Dog
和Cow
。
Animal
有一个抽象函数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]()
}
这会出错。我做错了什么?
答案 0 :(得分:2)
copy
中的Dog
方法与copy
中Animal
方法的签名不同(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()