Scala: Как я могу реализовать метод клонирования в суперклассе и использовать его в подклассе? - PullRequest
6 голосов
/ 08 января 2010

Возможно, я подхожу к этому неверно, но мне бы хотелось иметь такой объект:

class MyDataStructure {
  def myClone = {
    val clone = new MyDataStructure
    // do stuff to make clone the same as this
    ...
    clone
  }
}

class MyDataStructureExtended(val foo: String) extends MyDataStructure

Тогда:

val data = MyDataStructureExtended
val dataClone = data.clone
println(dataClone.foo)

Итак, проблема в том, что dataClone имеет тип MyDataStructure, а не MyDataStructureExtended, как я и надеялся.

Я думал о добавлении типа T к суперклассу, который подкласс может указать (например, сам), но это не показалось многообещающим.

Ответы [ 4 ]

5 голосов
/ 08 января 2010

Как вы и предполагали, вам нужны абстрактные типы или общие параметры. Требуется ли, чтобы MyDataStructure не было чертой или абстрактным классом? Следующее определяет MyDataStructure как абстрактный класс, но вы также можете сделать его характерным признаком.

abstract class MyDataStructure {
  type T
  def myClone: T
}

class MyDataStructureExtended(foo: String) extends MyDataStructure {
  type T = MyDataStructureExtended
  def myClone = new MyDataStructureExtended(foo)
}

Результаты интерпретатора Scala показывают, что метод myClone, определенный в MyDataStructureExtended, является правильным типом.

scala> val mde = new MyDataStructureExtended("foo")
val mde = new MyDataStructureExtended("foo")
mde: MyDataStructureExtended = MyDataStructureExtended@3ff5d699
scala> val cloned = mde.myClone
val cloned = mde.myClone
cloned: MyDataStructureExtended = MyDataStructureExtended@2e1ed620

Возможно, вы захотите ограничить T так, чтобы его тип мог соответствовать только типу подклассов MyDataStructure

abstract class MyDataStructure {
  type T <: MyDataStructure
  def myClone: T
}

Я не знаю ваших требований, но я полагаю, что Scala 2.8 будет иметь некоторые хорошие функциональные возможности с классами case и именованными аргументами, которые позволяют клонировать классы case с методом copy.

4 голосов
/ 08 января 2010

Если вы хотите минимизировать количество церемоний в подклассах, вот мое предложение:

class A extends Cloneable {
  protected[this] def myCloneImpl[T] = {
    val justLikeMe = this.clone
    // copy values and such.
    // Note that the Object.clone method already made a shallow copy, but you may want
    // to deepen the copy or do other operations.
    justLikeMe.asInstanceOf[T]
  }
  def myClone = myCloneImpl[A]
}

class B extends A {
  override def myClone = myCloneImpl[B]
}

Расширяя java.lang.Cloneable и вызывая метод Object.clone, вы гарантируете, что ваш тип времени выполнения совпадает с клонируемым объектом. Статический тип приводится с приведением типа (asInstanceOf [T]). Вам потребуется переопределить метод myClone в каждом подклассе и указать тип, но он должен быть однострочным.

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

Я думаю, что это может быть решением. Это не наследуется, и вы можете внести некоторые изменения, чтобы добиться своей цели. Удачи.

class CloneableClass extends scala.Cloneable {
   def myMethod: Unit = println("Inside "+this.getClass)
   override def clone(): CloneableClass =super.clone().asInstanceOf[this.type]
}

class CloneableDemo  {
  val cc = new CloneableClass
  val cc1 = cc.clone()
  cc1.myMethod
}

object CloneObject extends App {
  val cd = new CloneableDemo
}
0 голосов
/ 08 января 2010

Трудно сказать, правильно ли вы делаете это с таким расплывчатым описанием проблемы, но на самом деле это довольно просто сделать. Вы можете просто переопределить myclone в MyDataStructureExtended так, чтобы он возвращал более конкретный тип. Если у вас есть переменная более определенного типа, вы сможете использовать и более конкретный метод клонирования.

Пример кода на тот случай, если описание неясно:

class A {
  def getMe = this
}

class B extends A {
  override def getMe = this
  def isAnInstanceOfB = true
}

И соответствующий сеанс REPL:

scala> val a = new A
a: A = A@1a6eeab

scala> val b = new B
b: B = B@a36771

scala> a.getMe
res0: A = A@1a6eeab

scala> a.getMe.isAnInstanceOfB
<console>:7: error: value isAnInstanceOfB is not a member of A
       a.getMe.isAnInstanceOfB
           ^

scala> b.isAnInstanceOfB      
res2: Boolean = true

scala> b.getMe.isAnInstanceOfB
res3: Boolean = true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...