如何克隆案例类实例并仅更改 Scala 中的一个字段?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7249396/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to clone a case class instance and change just one field in Scala?
提问by Fran?ois Beausoleil
Let's say I have a case class that represents personas, people on different social networks. Instances of that class are fully immutable, and are held in immutable collections, to be eventually modified by an Akka actor.
假设我有一个案例类,它代表不同社交网络上的人物角色。该类的实例是完全不可变的,并保存在不可变集合中,最终由 Akka 演员修改。
Now, I have a case class with many fields, and I receive a message that says I must update one of the fields, something like this:
现在,我有一个包含许多字段的案例类,我收到一条消息,说我必须更新其中一个字段,如下所示:
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)
Notice I have to specify all fields, even though only one changes. Is there a way to clone existingPersona and replace only one field, without specifying all the fields that don't change? Can I write that as a trait and use it for all my case classes?
注意我必须指定所有字段,即使只有一个更改。有没有办法克隆 existingPersona 并只替换一个字段,而不指定所有不会更改的字段?我可以把它写成一个特征并将它用于我所有的案例类吗?
If Persona was a Map-like instance, it would be easy to do.
如果 Persona 是一个类似 Map 的实例,那将很容易做到。
回答by Nicolas
case classcomes with a copymethod that is dedicated exactly to this usage:
case class附带一个copy专门用于这种用法的方法:
val newPersona = existingPersona.copy(sentMessages =
existingPersona.sentMessages + newMessage)
回答by Kevin Wright
Since 2.8, Scala case classes have a copymethod that takes advantage of named/default params to work its magic:
从 2.8 开始,Scala 案例类有一个copy方法可以利用命名/默认参数来发挥它的魔力:
val newPersona =
existingPersona.copy(sentMessages = existing.sentMessages + newMessage)
You can also create a method on Personato simplify usage:
您还可以创建一个方法Persona来简化使用:
case class Persona(
svcName : String,
svcId : String,
sentMsgs : Set[String]
) {
def plusMsg(msg: String) = this.copy(sentMsgs = this.sentMsgs + msg)
}
then
然后
val newPersona = existingPersona plusMsg newMsg
回答by Jean-Philippe Pellet
existingPersona.copy(sentMessages = existingPersona.sentMessages + newMessage)
回答by Kaihua
Consider using lensin Shapelesslibrary:
考虑lens在Shapeless库中使用:
import shapeless.lens
case class Persona(serviceName : String,
serviceId : String,
sentMessages : Set[String])
// define the lens
val messageLens = lens[Persona] >> 'sentMessages
val existingPersona = Persona("store", "apple", Set("iPhone"))
// When you need the new copy, by setting the value,
val newPersona1 = messageLens.set(existingPersona)(Set.empty)
// or by other operation based on current value.
val newPersona2 = messageLens.modify(existingPersona)(_ + "iPad")
// Results:
// newPersona1: Persona(store,apple,Set())
// newPersona2: Persona(store,apple,Set(iPhone, iPad))
Moreover, in case you have nestedcase classes, the getterand settermethods can be a bit tedious to compose. It will be a good chance to simplify by using lens library.
此外,如果您有嵌套的case 类,getter和setter方法的组合可能有点乏味。这将是使用镜头库进行简化的好机会。
Please also refer to:
另请参阅:
回答by simbo1905
I didn't want to include a big library to do complex lenses that let you set values deep in nested case classes. It turns out it is just a few lines of codein the scalaz library:
我不想包含一个大的库来做复杂的镜头,让你在嵌套的案例类中设置深层次的值。事实证明,它只是scalaz 库中的几行代码:
/** http://stackoverflow.com/a/5597750/329496 */
case class Lens[A, B](get: A => B, set: (A, B) => A) extends ((A) => B) with Immutable {
def apply(whole: A): B = get(whole)
def mod(a: A, f: B => B) = set(a, f(this (a)))
def compose[C](that: Lens[C, A]) = Lens[C, B](
c => this(that(c)),
(c, b) => that.mod(c, set(_, b))
)
def andThen[C](that: Lens[B, C]) = that compose this
}
You can then create lenses that set deeply nested values far easier than using the built in copy feature. Here is a link to a big set if complex lenses that that my library uses to set heavily nested values.
然后,您可以创建比使用内置复制功能更容易设置深度嵌套值的镜头。这是一个大集合的链接,如果我的库使用它来设置大量嵌套的值的复杂镜头。

