Как клонировать экземпляр класса case и изменить только одно поле в Scala?

157

Скажем, у меня есть класс case, который представляет персонажи, людей в разных социальных сетях. Экземпляры этого класса полностью неизменяемы и хранятся в неизменных коллекциях, которые в конечном итоге будут изменены аккой Аккой.

Теперь у меня есть класс case со многими полями, и я получаю сообщение, в котором говорится, что я должен обновить одно из полей, примерно так:

case class Persona(serviceName  : String,
                   serviceId    : String,
                   sentMessages : Set[String])

// Somewhere deep in an actor
val newPersona = Persona(existingPersona.serviceName,
                         existingPersona.serviceId,
                         existingPersona.sentMessages + newMessage)

Заметьте, что я должен указать все поля, хотя только один изменяется. Есть ли способ клонировать existingPersona и заменять только одно поле без указания всех полей, которые не изменяются? Могу ли я написать это как свойство и использовать его для всех классов классов?

Если Persona был экземпляром, похожим на карту, это было бы легко сделать.

Теги:

3 ответа

266
Лучший ответ

case class поставляется с методом copy, который предназначен именно для этого использования:

val newPersona = existingPersona.copy(sentMessages = 
                   existingPersona.sentMessages + newMessage)
  • 5
    Где это задокументировано? Я не могу найти ссылку для копирования в «очевидных» местах, например, scala-lang.org/api/current/index.html .
  • 6
    Это особенность языка, вы можете найти его в спецификации Scala: scala-lang.org/docu/files/ScalaReference.pdf §5.3.2. Его нет в API, потому что он не является частью API;)
Показать ещё 9 комментариев
40

Начиная с 2.8, Scala классы case имеют метод copy, который использует свойства named/default для работы своей магией:

val newPersona =
  existingPersona.copy(sentMessages = existing.sentMessages + newMessage)

Вы также можете создать метод на Persona, чтобы упростить использование:

case class Persona(
  svcName  : String,
  svcId    : String,
  sentMsgs : Set[String]
) {
  def plusMsg(msg: String) = this.copy(sentMsgs = this.sentMsgs + msg)
}

затем

val newPersona = existingPersona plusMsg newMsg
9
existingPersona.copy(sentMessages = existingPersona.sentMessages + newMessage)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню