Подтвердить что ты не робот

Наследование case to case в Scala

У меня есть абстрактный класс, который я расширяю и делаю множество классов случаев. Теперь я хочу скопировать экземпляры этих классов case, просто изменяя первый параметр, поэтому я использую метод класса case < copy.

Так как я должен делать это для всех классов case, которые были расширены из общего абстрактного класса, а не для всех, я попытался сделать его общим и сделал абстрактным классом класс case.

Тогда Scala дает мне следующее:

класс case Осьминог имеет предки-предки-организмы, но наследование на случай болезни запрещено. Чтобы преодолеть это ограничение, используйте экстракторы для соответствия шаблону на нелистовых узлах.

Код:

abstract class Organism(legs: Int)
case class Octopus(override val legs: Int, weight: Double, ...)
case class Frog(override val legs: Int, ...)
def clone(o: Organism) = o.copy(legs = -1)

Это то, что я хочу сделать. Но если я не могу заставить метод clone работать, тогда мне придется делать копирование как для Octopus, так и Frog.

Любые предложения, чтобы уменьшить эту многословие?

4b9b3361

Ответ 1

Вы не можете полностью абстрагироваться от методов класса case copy. Я бы предложил использовать объективы из Shapeless или Monocle:

trait Organism { def legs: Int }
// monocle @Lenses uses a macro to generate lenses
@Lenses case class Octopus(override val legs: Int, weight: Double, ...)
  extends Organism
@Lenses case class Frog(val legs: Int, ...) extends Organism

def clone[O <: Organism](o: O, legsLens: Lens[O, Int]): O =
  legsLens.set(-1)(o)

val myOctopus = Octopus(8, 2.4, ...)
val myFrog = Frog(2, ...)

// use the generated Lenses
val cloneOctopus: Octopus = clone(myOctopus, Octopus.legs)
clone(myFrog, Frog.legs)

Ответ 2

Использование только стандартного scala такого обобщенного метода копирования в абстрактном (супер) классе не существует: как он узнает, как все подклассы могут быть клонированы/скопированы? Особенно, что новые подклассы могут быть добавлены в будущем.

Насколько я знаю, двумя основными подходами к реализации такого абстрактного метода являются:

1) создайте функцию, совпадающую по всем подклассам:

def clone(o: Organism) = o match {
  case o: Octopus => o.copy(legs = -1) 
  case f: Frog    => f.copy(legs = -1) 
}

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

2) добавьте метод makeClone к абстрактному API (зарезервированное имя clone):

abstract class Organism(legs: Int){
  def makeClone(legNumber: Int): Organism
}
case class Octopus(legs: Int, weight: Double) extends Organism(legs) {
  def makeClone(legNumber: Int) = this.copy(legs = legNumber)
}

Обратите внимание, что хотя функция в (1) всегда возвращает Organism, здесь метод Octopus.makeClone возвращает Octopus.