Scala:在 parent 方法中维护 child class?

Scala: Maintain child class in parent methods?

当你有parent时:

abstract class Parent {
   def something(arg: ???): Parent = ???
}

class Child extends Parent {}

我愿意

val updatedChild = new Child().something(...)

updatedChildChild 类型而不是 Parent 类型,这可能吗?

看来你可以做到:

class Parent[THIS <: Parent[THIS]] {
   def something: THIS
}

这似乎行得通。

我不确定这是否是您应该做的事情。

一种方法是参数化父级:

 abstract class Parent[T <: Parent[T]] {
    def something(arg: Foo): T
 }

 class Child(val foo: String) extends Parent[Child] {
    def something(arg: String) = return new Child(arg)
 }

有时,您也可以使用 this.type:

class Parent {
  def something(arg: Foo): this.type = this
}
class Child {
   override def something(arg: Foo) = this
}

但是后一种方法只有在你想要 return 是 this 时才有效(this.type 不是 ParentChild,而是只有一个实例的特定类型 - this).

这里建议实际编译:

abstract class Parent[Repr <: Parent[Repr]] {
  def something(arg: Int): Repr
}

这是您可以做的事情,至少没有明确反对。标准集合库经常使用它,例如参见IterableLike 作为这种 F 界多态性的典型例子。

Andrey 和 Dima 的回答都涵盖了一种仅使用面向对象模式来解决问题的方法。

但是我想指出另一种方法叫做 typeclasses (在函数式语言中更常见), 如果您打算使用您的界面编写通用函数,这将很有帮助。

首先,您没有父级 class,而是拥有一个 接口,它描述了可以在类型 class 的实例上执行的操作.

trait Typeclass[T] {
  def something(t: T)(arg: Foo): T
}

然后,您将定义您的类型,这次它们不扩展任何父级 class,因此它们不必重写任何内容。

class Child {
  ...
}

现在,您必须证明您的类型是 class.
类型的一个实例 (一个常见的地方是在 class 的伴生对象中).

object Child {
  implicit final val ChildTypeclass: Typeclass[Child] = new Typeclass[Child] {
    override def something(child: Child)(arg: Foo): Child = ???
  }
}

最后,您定义了一个泛型方法,它可以对任何类型 T 进行操作,只要该类型存在您的类型的实例class。

def generic[T](t: T, arg: Foo)(implicit tt: Typeclass[T]): T =
  tt.something(t)(arg)

奖金,如果你想恢复 "dot notation" 你可以在你的类型中添加一个 Ops 模式class。

object syntax {
  object typeclass {
     implicit final class TypeclassOps[T](val t: T) extends AnyVal {
       final def something(arg: Foo)(implicit tt: Typelcass[T]) =
         tt.something(t)(arg)
     }
  }
}

import syntax.typeclasss._

def generic[T: Typelcass](t: T, arg: Foo): T
  t.something(arg)

val newChild = generic(new Child, new Foo)
// newChild: Child = ???

此外,一种常见的方法是在 class 中定义 something 方法,然后类型 class 实例将调用转发到 class 中定义的方法,这样你就可以在 Child 的任何实例中使用你的方法,而不必将所有类型 class 机器。

我必须说这对于非常高级的抽象非常有用,您计划为其提供许多类型的实例(甚至是您无法控制的类型,如任何标准集合类型) 并编写可以对其中任何一个进行操作的非常通用的函数。
如果不是,F 有界类型似乎是更合理的解决方案。