【问题标题】:How to make a parent class return a type which can match subtypes?如何使父类返回可以匹配子类型的类型?
【发布时间】:2021-10-28 23:50:31
【问题描述】:
如何在父类中定义返回类型以匹配子实例类?
在下面的示例中,需要定义 echo 函数,使其返回调用 this 的子类的对象。
trait A[T] {
def echo(a: T): T
}
class B extends A[B] {
override def echo(x: B):B = x
}
class C extends B {
def repeat(x: B): B = echo(x)
}
val b = new B()
val c = new C()
// Fails with error value repeat is not a member of B
c.repeat(b).repeat(b)
// Compilation error
// Found: B
// Required: D
class D extends B {
def repeat(x: B): D = echo(x)
}
}
【问题讨论】:
标签:
scala
generics
covariance
【解决方案1】:
你到底想做什么?
如果你跟踪你的调用链,你会看到c.repeat(b) 返回的b:B 的实例显然没有repeat 方法,该方法在C 中定义。
换句话说,在您的代码中,b.echo(x:B) 返回 x,而不是 this!
也许您想从C.repeat 返回this?这应该有效:
class C extends B {
def repeat(x: B): C = {
echo(x)
this
}
}
val b = new B()
val c = new C()
c.repeat(b).repeat(b)
【解决方案2】:
正如@Aivean 提到的,您的方法repeat 是在类C 上定义的,并返回其父类B 的实例,该实例没有repeat 方法。
所以你不能像这样调用 repeat 两次:
val tmpB = c.repeat(b) // tmpB is an instance of B
tmpB.repeat(b) // fail cuz B has no "repeat" method
就是这样。
现在回答主要问题:“如何让父类返回可以匹配子类型的类型?”
与你对 trait A 所做的相同,但在其参数类型上添加约束,以便 T 必须是 A:
trait A[T<:A[T]]
class B extends A[B]
在这个很好的答案中阅读更多关于“F-bounded polymorphism”的信息:https://stackoverflow.com/a/21699765/1206998