如何使父类返回可以匹配子类型的类型?

Posted

技术标签:

【中文标题】如何使父类返回可以匹配子类型的类型?【英文标题】: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)


【问题讨论】:

这是一个常见问题解答:docs.scala-lang.org/tutorials/FAQ/… 【参考方案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://***.com/a/21699765/1206998

【讨论】:

以上是关于如何使父类返回可以匹配子类型的类型?的主要内容,如果未能解决你的问题,请参考以下文章

python正则匹配

MS 访问错误。 3464,过滤器类型不匹配,如何正确设置过滤器?

一个try可以跟进多个catch语句,用于处理不同情况,当一个try只能匹配一个catch

比较两个记录集变量给出类型不匹配

@AspectJ support (good)

如何检查 Json 是不是匹配特定的 C# 类型?