如何克隆案例类实例并在Scala中只更改一个字段?

Fra*_*eil 205 scala

假设我有一个代表角色的案例类,不同社交网络上的人.该类的实例是完全不可变的,并且保存在不可变集合中,最终由Akka actor修改.

现在,我有一个包含许多字段的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)
Run Code Online (Sandbox Code Playgroud)

注意我必须指定所有字段,即使只有一个更改.有没有办法克隆existingPersona并只替换一个字段,而不指定所有不更改的字段?我可以将其作为特征编写并将其用于我的所有案例类吗?

如果Persona是一个类似Map的实例,那么很容易做到.

Nic*_*las 314

case class附带一个copy专门用于此用法的方法:

val newPersona = existingPersona.copy(sentMessages = 
                   existingPersona.sentMessages + newMessage)
Run Code Online (Sandbox Code Playgroud)

  • 它是该语言的一个特性,您可以在Scala规范中找到它:http://www.scala-lang.org/docu/files/ScalaReference.pdf§5.3.2.它不在API中,因为它不是API的一部分;) (6认同)
  • 记录在哪里?我找不到在"明显"的地方复制的参考资料,例如http://www.scala-lang.org/api/current/index.html. (5认同)
  • 这会很好.但在这里,弗朗索瓦(如果我是对的)的问题是他不知道如果他宣布一个"案例类"他会有一个`copy`方法. (4认同)
  • @JonathanNeufeld在这种感觉下,您将在纯粹的fp阵营中结交许多不友善的人。我倾向于同意你的看法。 (2认同)

Kev*_*ght 45

从2.8开始,Scala案例类有一种copy方法可以利用命名/默认参数来实现它的魔力:

val newPersona =
  existingPersona.copy(sentMessages = existing.sentMessages + newMessage)
Run Code Online (Sandbox Code Playgroud)

您还可以创建方法Persona以简化使用:

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

然后

val newPersona = existingPersona plusMsg newMsg
Run Code Online (Sandbox Code Playgroud)


Jea*_*let 10

existingPersona.copy(sentMessages = existingPersona.sentMessages + newMessage)
Run Code Online (Sandbox Code Playgroud)