Scala: Поддерживать дочерний класс в родительских методах? - PullRequest
0 голосов
/ 24 декабря 2018

Если у вас есть родитель:

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

и

class Child extends Parent {}

Я бы хотел, чтобы

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

updatedChild было типа Childа не типа Parent это возможно?

Ответы [ 4 ]

0 голосов
/ 24 декабря 2018

Ответы Андрея и Димы охватывают один способ решения проблемы с использованием только oo-шаблонов.

Однако я хотел бы отметить другой подход, называемый typeclasses (которыйчаще встречается в функциональных языках) , что было бы полезно, если вы планируете писать универсальные функции с использованием вашего интерфейса.

Во-первых, вместо родительского класса у вас есть интерфейс который описывает операции, которые могут выполняться над экземплярами класса типов.

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)

Бонус, если вы хотите восстановить "точечную нотацию" , вы можете добавить шаблон 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должен сказать, что это полезно для абстракций очень высокого уровня, для которых вы планируете предоставлять экземпляры для многих типов (даже типов вне вашего контроля, как любой из стандартных типов коллекций) и писать очень общие функции, которые могут работатьна любом из них.
Если нет, F-ограниченные типы кажутся более рациональным решением.

0 голосов
/ 24 декабря 2018

Один из способов сделать это - параметризовать родителя:

 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 - это не Parent или Child, а конкретный тип, который имеет только один экземпляр - this).

0 голосов
/ 24 декабря 2018

Вот предложение, которое на самом деле компилирует :

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

Это то, что вы можете сделать, по крайней мере, это явно не рекомендуется.Стандартная библиотека коллекций часто его использует, например, IterableLike в качестве типичного примера такого F-ограниченного полиморфизма.

0 голосов
/ 24 декабря 2018

Кажется, что вы можете сделать:

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

И это похоже на работу.

Я не уверен, что это то, что вы должны сделать, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...