2010-11-07 3 views
5

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

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 

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

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

+0

Связанный вопрос: http://stackoverflow.com/questions/2911562/case-class-copy-method-abstraction –

+1

http://scala-programming-language.1934581.n4.nabble.com/Question-on- case-class-and-copy-method-td1936310.html –

ответ

3

Поведение, которое вы пытаетесь достичь, не реализуется. 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 и уменьшите количество изменений, если ваши классы классов меняются.

+0

Мне нравится первое предложение. Благодаря! – tbruhn

7

Если вы параметризуете свой базовый класс и также определяете метод абстрактной копии, вы можете заставить подклассы возвращать экземпляры своих типов из метода копирования. В этом случае вы хотите, чтобы 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)) 

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

Смежные вопросы