2

当你有父母时:

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

class Child extends Parent {}

我想

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

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

4

4 回答 4

5

一种方法是参数化父级:

 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
}

但是后一种方法仅在您想要返回的只是this(this.type不是Parentor Child,而是只有一个实例的特定类型 - this) 时才有效。

于 2018-12-24T19:12:46.687 回答
2

这是一个实际编译的提案:

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

这是您可以做的事情,至少没有明确劝阻。标准集合库大量使用它,例如,将IterableLike视为此类 F 有界多态性的典型示例。

于 2018-12-24T19:26:13.457 回答
1

看来您可以这样做:

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

这似乎奏效了。

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

于 2018-12-24T19:10:36.870 回答
1

Andrey 和 Dima 的答案都涵盖了一种仅使用 oo 模式来解决问题的方法。

但是,我想指出另一种称为类型类 (在函数式语言中更常见)的方法,如果您打算使用您的接口编写通用函数,这将很有帮助。

首先,您没有父类,而是有一个接口来描述可以在类型类的实例上执行的操作。

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

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

class Child {
  ...
}

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

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

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

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

奖励,如果你想恢复“点符号”,你可以在你的 Typeclass 中添加一个 Ops 模式。

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 = ???

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

I must say that this is useful for very high-level abstractions to which you plan to provide instances for many types (even types outside your control like any of the standard collection types) and write very generic functions that can operate on any of these.
If not, F-bounded types seems like the more rational solution.

于 2018-12-24T19:35:33.660 回答