Scala case class uses shallow copy or deep copy?

时光毁灭记忆、已成空白 提交于 2020-02-20 07:18:59

问题


case class Person(var firstname: String, lastname: String)

val p1 = Person("amit", "shah")
val p2 = p1.copy()
p1.firstname = "raghu"
p1
p2

p1 == p2

As i went through some documentation which says scala copy method of case class uses shallow copy

but output of this example i am not able to crack

i have created copy as person p2 from p1 and then i have changed p1.firstname to "raghu"

so, in case of shallow copy it should change value of p2.firstname but this is not happening here

reference: https://docs.scala-lang.org/tour/case-classes.html


回答1:


Your confusion is about the difference between variables and values.

So, when you do something like,

val p1 = Person("amit", "shah")
val p2 = p1.copy()

Then p2 is a shallow copy of p1, so the variables p1.firstname and p2.firstname point to the same value of String type which is "amit".

When you are doing p1.firstname = "raghu", you are actually telling variable p1.firstname to point to a different value of String type which is "raghu". Here you are not changing the value itself but the variable.

If you were to change to value itself, then both p1 and p2 will reflect the change. Unfortunately, String values are immutable in Scala, so you can not modify a String value.

Let me show you by using something modifiable like a ArrayBuffer.

scala> import scala.collection.mutable.ArrayBuffer
// import scala.collection.mutable.ArrayBuffer

scala> case class A(s: String, l: ArrayBuffer[Int])
// defined class A

scala> val a1 = A("well", ArrayBuffer(1, 2, 3, 4))
// a1: A = A(well,ArrayBuffer(1, 2, 3, 4))

scala> val a2 = a1.copy()
// a2: A = A(well,ArrayBuffer(1, 2, 3, 4))

// Lets modify the `value` pointed by `a1.l` by removing the element at index 1
scala> a1.l.remove(1)
// res0: Int = 2

// You will see the impact in both a1 and a2.

scala> a1
// res1: A = A(well,ArrayBuffer(1, 3, 4))

scala> a2
//res2: A = A(well,ArrayBuffer(1, 3, 4))



回答2:


You can imagine the values of String variables, as being references to Strings stored in a Value Store somewhere.

With a shallow copy, all values are still pointed at their original values, there isn't a "second string" created.

However, since the JVM treats string references like values, when firstname is assigned it is now pointing to "raghu"

If we instead wrap the string in another class, let's call it case class Box(var s:String)

Then the JVM (and thus scala) will be using references to orange 'boxes' instead of strings.

case class Person(var firstname: Box, lastname: Box)

val p1 = Person(Box("amit"), Box("shah"))
val p2 = p1.copy()
p1.firstname = Box("raghu")

The same exact graphic applies, because it was a shallow copy.

all the references are copies, and now point to the box, in orange.

if instead of changing the reference to a new box, you change the string inside the box.

p1.firstname.s = "raghu" what you are instead doing is replacing the value inside the box.

If there were some theoretical "deep copy" method.

It would copy the references, the boxes, and the strings inside.


Strings are strange on the JVM. they act like values, and sometimes singleton values, and their reference equality (in java) is messed up because of it, but this is an implementation detail, hidden to both Java and Scala. So we can treat Strings as values. (see What is Java String interning? for more on this, but it may be too advanced for now) and a Scala thread: https://www.scala-lang.org/old/node/10049.html



来源:https://stackoverflow.com/questions/52966711/scala-case-class-uses-shallow-copy-or-deep-copy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!