Иерархия классов дел Scala - PullRequest
       13

Иерархия классов дел Scala

5 голосов
/ 07 ноября 2010

У меня возникли некоторые трудности при разработке моих тематических классов. Упрощенная версия выглядит так:

abstract class Base(s: Option[String]) {
   //code
}

case class CaseClass(s: Option[String] = None) extends Base(s) {
    //code
}

И у меня есть метод, где я хочу сделать что-то вроде:

  def method(base : Base) = {
     //code
     base copy (s = Some("string"))
  }

Конечно, я получаю:

 value copy is not a member of Base

Итак, я хочу создать новый экземпляр на основе моего базового класса (который не является классом дел). Очевидно, что никто не может сделать это. Но как бы вы решили это элегантно?

Заранее спасибо!

Ответы [ 2 ]

7 голосов
/ 07 ноября 2010

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

abstract class Base[T](s: Option[String]) {
  def copy(in: Option[String]) : T
}

case class CaseClass(s: Option[String]) extends Base[CaseClass](s) {
  def copy(in: Option[String]) = CaseClass(in)
}

case class OtherClass(s: Option[String]) extends Base[OtherClass](s) {
  def copy(in: Option[String]) = OtherClass(in)
}

def method[T <: Base[T]](base: T) : T = {
  base.copy(Some("String"))
}


scala> method(CaseClass(None))
res1: CaseClass = CaseClass(Some(String))

scala> method(OtherClass(Some("hi")))
res2: OtherClass = OtherClass(Some(String))

Другие подклассы Base будут возвращать свои собственные типы.Параметр типа в #method определяется верхней границей Base [T].Это означает, что T должен быть любым подтипом Base [T], и именно это позволяет вам предоставлять экземпляры CaseClass и OtherClass в качестве параметров для этого метода.

3 голосов
/ 07 ноября 2010

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

Вы можете переопределить copy с чертами, но он не будет таким гибким, как сгенерированный (вам придется обновлять базовые черты, реализации copy и method каждый раз, когда набор полей в случае изменения класса):

sealed trait Base[T] {
   val s: Option[String]
   def copy(s: Option[String]) : T
}

case class CaseClass(override val s: Option[String] = None) extends Base[CaseClass] {
    override def copy(s: Option[String]) = CaseClass(s)
}

def method[T <: Base[T]](base : Base[T]) = base copy (s = Some("strng"))

В качестве альтернативы вы можете реализовать method следующим образом:

case class CaseClass(s: Option[String] = None)

def method[X <: {def copy(s: Option[String]):X}](base : X) = 
    base copy(s = Some("string"))

scala> method(CaseClass())
res4: CaseClass = CaseClass(Some(string))

Таким образом, вам не понадобится черта Base и уменьшите количество изменений, если ваши классы дел изменятся.

...