2010-11-07 9 views
5

Ho avuto alcune difficoltà nella progettazione delle mie case classes. Una versione semplificata assomiglia:Gerarchia classe case Scala

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

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

e ho un metodo in cui voglio fare qualcosa di simile:

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

Naturalmente ottengo:

value copy is not a member of Base 

Quindi quello che voglio do è creare una nuova istanza in base alla mia classe base (che non è una classe case). Ovviamente non si può fare questo. Ma come risolverebbe questo in modo elegante?

Grazie in anticipo!

+0

questione connessa: 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 –

risposta

3

Il comportamento che stai cercando di raggiungere non è implementabile. Il metodo copy di una classe case viene generato automaticamente dal compilatore e una volta aggiunto un metodo chiamato copy all'implementazione, il compilatore non genererà alcuno zucchero.

È possibile reimplementare copy con tratti, ma non sarà flessibile come il generato uno (si dovrà aggiornare la caratteristica di base, copy e method implementazioni ogni volta il campo-set di un cambiamento caso di classe):

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

in alternativa, è possibile implementare method come segue:

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

Quindi non avrai bisogno del tratto Base e riduci il numero di modifiche, se cambiano le tue case classes.

+0

Mi piace il primo suggerimento. Grazie! – tbruhn

7

Se si parametrizza la classe base e si definisce anche il metodo di copia astratta, è possibile fare in modo che le sottoclassi restituiscano le istanze dei propri tipi dal metodo di copia. In questo caso, si desidera che CaseClass restituisca una CaseClass, presumibilmente.

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

Altre sottoclassi di Base restituirebbero i propri tipi. Il parametro type su #method è definito con un limite superiore di Base [T]. Ciò significa che T deve essere qualsiasi sottotipo di Base [T] ed è ciò che consente di fornire istanze di CaseClass e OtherClass come parametri a tale metodo.