Frage Scala: Fallklassen mit Merkmal kopieren


Ich bin ziemlich neu in Scala und ich habe eine Frage über den besten Weg, eine Fallklasse zu kopieren, während Daten, die aus Merkmalen stammen, erhalten bleiben. Nehmen wir zum Beispiel Folgendes an:

trait Auditing {

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

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

val user = User("Joe", "joe@blah.com")

Dann möchte ich eine neue Kopie mit einem geänderten Parameter erstellen:

val user2 = user.copy(email = "joe@newemail.com")

Im obigen Beispiel wird die Eigenschaft createTime nicht übernommen, da sie nicht im Konstruktor der Benutzer-Fallklasse definiert ist. Meine Frage ist also: Unter der Annahme, dass das Verschieben von createTime in den Konstruktor keine Option ist, wie erhält man am besten eine Kopie des User-Objekts, das den Wert aus dem Merkmal enthält?

Ich benutze Scala 2.9.1

Danke im Voraus! Joe


10
2017-11-02 00:48


Ursprung


Antworten:


Sie können die Kopiermethode mit diesem Verhalten überschreiben.

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

6
2017-11-02 02:25



Während ich keine andere Lösung als die von Reuben sehe, verstehe ich nicht die Anforderung, die Konstruktorargumente unberührt zu lassen. Dies wäre die natürlichste Lösung:

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

Wenn Sie nicht möchten, dass der Benutzer überschreiben kann createTime, Sie können immer noch verwenden:

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

Der einzige Nachteil ist, dass Sie schreiben müssen new User("Joe", "joe@blah.com"), da der primäre Konstruktor jetzt privat ist.


3
2017-11-02 07:35



Sie sollten besser keine Fallklasse verwenden. Sie können das einfach implementieren Funktionalität, die Sie selbst brauchen. Der folgende Code implementiert die gewünschte Kopiermethode, einen Konstruktor ohne Neu, verbirgt den ursprünglichen Konstruktor und erstellt einen Extraktor, damit Sie Benutzer in Fallanweisungen verwenden können.

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

0
2018-05-06 05:39