Scala案例类使用浅拷贝还是深拷贝?

Nav*_*lot 8 scala shallow-copy

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

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

p1 == p2
Run Code Online (Sandbox Code Playgroud)

正如我通过一些文档说scala复制方法的案例类使用浅拷贝

但是这个例子的输出我无法破解

我已经从p1创建了副本p2,然后我将p1.firstname更改为"raghu"

因此,如果是浅拷贝,它应该改变p2.firstname的值,但这不会发生在这里

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

Sar*_*ngh 8

你的困惑是约之间的区别variablesvalues.

那么,当你做某事时,

val p1 = Person("amit", "shah")
val p2 = p1.copy()
Run Code Online (Sandbox Code Playgroud)

然后p2是一个浅的副本p1,所以variables p1.firstnamep2.firstname指向相同valueString类型"amit".

当你这样做时p1.firstname = "raghu",你实际上是在告诉变量p1.firstname指向不同valueString类型"raghu".在这里你不是改变价值本身而是改变价值variable.

如果你要改变value自己,那么这两个p1p2将反映这一变化.不幸的是,String值在Scala中是不可变的,因此您无法修改String值.

让我通过使用可修改的东西来向你展示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))
Run Code Online (Sandbox Code Playgroud)


Rya*_*ach 6

您可以想象String变量的值,因为它是对存储在Value Store中的字符串的引用. 在此输入图像描述

对于浅拷贝,所有值仍然指向其原始值,没有创建"第二个字符串".

但是,由于JVM将字符串引用视为值,因此在分配firstname时,它现在指向"raghu"

如果我们将字符串包装在另一个类中,那就让我们调用它 case class Box(var s:String)

然后JVM(以及scala)将使用对橙色"框"的引用而不是字符串.

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

val p1 = Person(Box("amit"), Box("shah"))
val p2 = p1.copy()
p1.firstname = Box("raghu")
Run Code Online (Sandbox Code Playgroud)

同样的图形适用,因为它是一个浅的副本.

所有引用都是副本,现在指向橙色框.

如果不是更改对新框的引用,则更改框内的字符串.

p1.firstname.s ="raghu"你正在做的是替换盒子里面的值.

在此输入图像描述

如果有一些理论上的"深层复制"方法. 在此输入图像描述

它会复制里面的引用,框和字符串.


JVM上的字符串很奇怪.它们就像值一样,有时候是单例值,它们的引用相等(在java中)因为它而搞砸了,但这是一个实现细节,对Java和Scala都是隐藏的.所以我们可以将字符串视为值.(请参阅什么是Java String interning?有关此内容的更多信息,但现在可能过于先进)和Scala主题:https://www.scala-lang.org/old/node/10049.html