2010-11-07 11 views
5

Ich habe einige Schwierigkeiten beim Entwerfen meiner Fallklassen. Eine vereinfachte Version wie folgt aussieht:Scala Fall Klassenhierarchie

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

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

Und ich habe eine Methode, wo ich wie etwas tun wollen:

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

Natürlich bekomme ich:

value copy is not a member of Base 

Also, was ich will do erstellt eine neue Instanz basierend auf meiner Basisklasse (die keine Fallklasse ist). Offensichtlich kann man das nicht tun. Aber wie würdest du das elegant lösen?

Vielen Dank im Voraus!

+0

Verwandte Frage: 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 –

Antwort

3

Das Verhalten, das Sie erreichen möchten, ist nicht implementierbar. copy Methode einer Fallklasse wird vom Compiler automatisch generiert. Sobald Sie Ihrer Implementierung eine Methode namens copy hinzugefügt haben, generiert der Compiler keinen Zucker mehr.

Sie können copy mit Zügen neu implementieren, aber es wird nicht so flexibel wie die erzeugte ein (Sie werden das Basismerkmal aktualisieren müssen, copy und method Implementierungen jedes Mal, wenn die von einem Fall, Klassenänderungen Feld eingestellt):

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")) 

Alternativ können Sie method wie folgt implementieren:

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)) 

Sie brauchen also keine Base Eigenschaft und reduzieren die Anzahl der Änderungen, wenn sich Ihre Fallklassen ändern.

+0

Ich mag den ersten Vorschlag. Vielen Dank! – tbruhn

7

Wenn Sie Ihre Basisklasse parametrisieren und auch dort die abstrakte Kopiermethode definieren, können die Unterklassen Instanzen ihrer eigenen Typen von der Kopiermethode zurückgeben. In diesem Fall soll CaseClass vermutlich eine CaseClass zurückgeben.

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)) 

Andere Unterklassen von Base würden ihre eigenen Typen zurückgeben. Der Typparameter in #method ist mit einer oberen Grenze von Base [T] definiert. Dies bedeutet, dass T ein beliebiger Untertyp von Base [T] sein muss und Ihnen ermöglicht, Instanzen von CaseClass und OtherClass als Parameter für diese Methode bereitzustellen.