2012-11-02 14 views
10

Sono abbastanza nuovo su Scala e ho una domanda sul modo migliore di copiare una classe di case preservando i dati che provengono dai tratti. Per esempio, diciamo che ho il seguente:Scala: copia di classi di casi con tratto

trait Auditing { 

    var createTime: Timestamp = new Timestamp(System.currentTimeMillis) 
} 

case class User(val userName: String, val email: String) extends Auditing 

val user = User("Joe", "[email protected]") 

poi voglio fare una nuova copia con un parametro modificato:

val user2 = user.copy(email = "[email protected]") 

Ora, nell'esempio di cui sopra, la CreateTime proprietà non ottiene copiato perché non è definito nel costruttore della classe case User. Quindi la mia domanda è: assumendo che spostare createTime nel costruttore non sia un'opzione, qual è il modo migliore per ottenere una copia dell'oggetto User che includa il valore dal tratto?

sto usando Scala 2.9.1

Grazie in anticipo! Joe

+0

non c'è molto opzioni di fronte a voi: o si sceglie di implementare manualmente un tale metodo che produrrà la copia che si desidera nella dichiarazione della classe 'user' caso o si utilizza Scala 2.10 macro dispongono per automatizzare questo. La seconda opzione sicuramente non sarà un compito facile per un principiante. –

+1

@NikitaVolkov Se tu fossi disposto a fornire a me/noi un esempio di come lo faresti con i macro, sarebbe più che ottimo. –

+2

@mhs Mi iscrivo al club. Sono una newbee in macro, ecco perché non l'ho postata come risposta. Ma [ecco come] (http://stackoverflow.com/a/10397595/485115) ho risolto un compito molto simile con la 'Toolbox' api. La risposta accettata è basata su macro, ma penso che non supporti l'ultima versione di Scala. –

risposta

6

È possibile sovrascrivere il metodo di copia con tale comportamento.

case class User(val userName: String, val email: String) extends Auditing 
{ 
    def copy(userName = this.userName, email = this.email) { 
    val copiedUser = User(userName, email) 
    copiedUser.createTime = createTime 
    copiedUser  
    } 
} 
3

Mentre vedo altra soluzione che Reuben di, non capisco l'obbligo di lasciare le args costruttore intatta. Questa sarebbe la soluzione più naturale:

case class User(userName: String, email: String, 
    override val createTime:Timestamp = new Timestamp(System.currentTimeMillis)) 
     extends Auditing 

Se non si desidera che l'utente sia in grado di sovrascrivere createTime, è comunque possibile utilizzare:

case class User private (userName: String, email: String, 
    override val createTime:Timestamp) extends Auditing { 
    def this(userName: String, email: String) = 
    this(userName, email, new Timestamp(System.currentTimeMillis)) 
} 

L'unico svantaggio è che è necessario scrivere new User("Joe", "[email protected]"), poiché il costruttore principale è ora privato.

0

Potrebbe essere meglio non utilizzare una classe di casi. Puoi facilmente implementare la funzionalità di cui hai bisogno tu stesso. Il codice seguente implementa il metodo di copia che si desiderava, un costruttore senza nuovo, nasconde il costruttore originale e crea un estrattore in modo che sia possibile utilizzare User in case statement.

class User private(val userName: String, 
        val email: String, 
        val timeStamp: Timestamp = 
        new Timestamp(System.currentTimeMillis)) { 

    def copy(uName: String = userName, 
      eMail: String = email) = 
    new User(uName, eMail, timeStamp) 
} 

object User { 
    def apply(userName: String, email: String) = 
    new User(userName, email) 

    def unapply(u: User) = Some((u.userName, u.email, u.timeStamp)) 
} 
Problemi correlati