【问题标题】: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

    【讨论】:

      猜你喜欢
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-25
      • 1970-01-01
      • 2016-10-29
      相关资源
      最近更新 更多