Scala 定义方法以返回扩展它的类的类型

Scala 定义方法以返回扩展它的类的类型,scala,types,Scala,Types,我希望能够做到这样: trait A { def f(): ???_THE_EXTENDING CLASS } class C extends A { def f() = self } class D extends A { def f() = new D } class Z extends D { def f() = new Z } 鉴于上面的代码,下面的代码将无法编译 class Bad1 extends A { def f() = "unrelated string"

我希望能够做到这样:

trait A {
  def f(): ???_THE_EXTENDING CLASS
}
class C extends A {
  def f() = self
}
class D extends A {
  def f() = new D
}
class Z extends D {
  def f() = new Z
}
鉴于上面的代码,下面的代码将无法编译

class Bad1 extends A {
  def f() = "unrelated string"
}
class Bad2 extends A {
  def f() = new C // this means that you can't just define a type parameter on
                  // A like A[T <: A] with f() defined as f: T
}
class Bad3 extends D // f() now doesn't return the correct type
Bad1类扩展了{
def f()=“不相关的字符串”
}
类Bad2扩展了{
def f()=new C//这意味着您不能仅在上定义类型参数

//A就像[T我恐怕不可能从扩展类中知道什么是扩展类

最接近你想要的是类似于奇怪的重复模板模式(CRTP),它是C++所熟知的。

trait A[T <: A[T]] {
  def f(): T;
}

class C extends A[C] {
  def f() = new C
}

class D extends A[D] {
  def f() = new D
}

trait A[T您可以做的一件事是返回type
this.type

trait A {
  def f(): this.type
}

class C extends A {
  def f() = this
}

class D extends A {
  def f() = this
}

class Z extends D {
  override def f() = this
  def x = "x"
}

println((new Z).f().x)

这对构建器很有用。

这里是另一种可能的解决方案。它是自类型+类型参数的组合:

trait A[T <: A[T]] { self: T =>
  def f(): T
}

class Z extends A[Z] {
  override def f() = new Z
  def x = "x"
}

println((new Z).f().x)
trait A[T
定义f():T
}
类Z扩展了A[Z]{
覆盖def f()=新Z
def x=“x”
}
println((新的Z.f().x)
您可以在此处找到有关此解决方案的更多信息:


这并不适用于所有情况,尽管它总比没有好。有关更多详细信息,请参阅文章中的“编辑”。@aharon:是的,
这个.type
是一种单例类型。你可以对它进行更多了解。因此,它并不适用于所有可能的情况……这效果更好,但有没有办法绕过第二次编辑中显示的问题?这很有效更好,但是有没有办法绕过第二次编辑中显示的问题?
trait A {
  def f(): this.type
}

class C extends A {
  def f() = this
}

class D extends A {
  def f() = this
}

class Z extends D {
  override def f() = this
  def x = "x"
}

println((new Z).f().x)
trait A[T <: A[T]] { self: T =>
  def f(): T
}

class Z extends A[Z] {
  override def f() = new Z
  def x = "x"
}

println((new Z).f().x)