Scala: Копирование классов классов с признаком

Я новичок в Scala, и у меня есть вопрос о наилучшем способе копирования класса case при сохранении данных, которые поступают из свойств. Например, допустим, что у меня есть следующее:

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

Затем я хочу создать новую копию с одним измененным параметром:

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

Теперь, в приведенном выше примере, свойство createTime не копируется, потому что оно не определено в конструкторе класса case пользователя. Поэтому мой вопрос: если предположить, что перемещение createTime в конструктор не является опцией, каков наилучший способ для получения копии объекта User, который включает в себя значение из признака?

Я использую Scala 2.9.1

Спасибо заранее! Джо

Ответ 1

Вы можете переопределить метод копирования с этим поведением.

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

Ответ 2

Пока я не вижу другого решения, кроме Рувина, я не понимаю требования оставить конструктор args нетронутым. Это было бы наиболее естественным решением:

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

Если вы не хотите, чтобы пользователь мог перезаписать createTime, вы все равно можете использовать:

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

Единственным недостатком является то, что вам нужно написать new User("Joe", "[email protected]"), поскольку основной конструктор теперь является приватным.

Ответ 3

Возможно, вам лучше не использовать класс case. Вы можете легко реализовать функциональность, в которой вы нуждаетесь. В приведенном ниже коде реализован метод копирования, который вам нужен, конструктор без нового, скрывает исходный конструктор и создает экстрактор, чтобы вы могли использовать User в операторах case.

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