Класс случая Scala использует поверхностное или глубокое копирование? - PullRequest
0 голосов
/ 24 октября 2018
case class Person(var firstname: String, lastname: String)

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

p1 == p2

Когда я просмотрел некоторую документацию, в которой говорится, что метод scala-копирования класса case использует мелкую копию

, но при выводе этого примера я не могу взломать

Я создал копиюкак человек p2 из p1, а затем я изменил p1.firstname на "raghu"

, поэтому в случае мелкой копии это должно изменить значение p2.firstname, но здесь этого не происходит

ссылка: https://docs.scala -lang.org / tour / case-classes.html

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Вы можете представить значения переменных String как ссылки на строки, хранящиеся где-то в хранилище значений.enter image description here

При мелкой копии все значения по-прежнему указывают на свои исходные значения, "вторая строка" не создается.

Однако, посколькуJVM обрабатывает строковые ссылки как значения, когда имя присваивается, теперь оно указывает на «raghu»

Если мы вместо этого обернем строку в другом классе, назовем ее case class Box(var s:String)

ТогдаJVM (и, следовательно, scala) будет использовать ссылки на оранжевые «ящики» вместо строк.

case class Person (var firstname: Box, фамилия: Box)

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

То же самое точнорисунок применяется, потому что это была мелкая копия.

все ссылки являются копиями и теперь указывают на прямоугольник оранжевого цвета.

если вместо изменения ссылкив новый блок вы меняете строку внутри блока.

p1.firstname.s = "raghu" вместо этого вы заменяете значение внутри блока.

enter image description here

Если был какой-то теоретический метод "глубокого копирования".enter image description here

Это скопировало бы ссылки, поля и строки внутри.


Строки странные в JVM.они действуют как значения, а иногда и одноэлементные значения, и из-за этого нарушается их ссылочное равенство (в java), но это деталь реализации, скрытая как для Java, так и для Scala.Таким образом, мы можем рассматривать строки как значения.(см. Что такое интернирование Java String? , чтобы узнать больше об этом, но это может быть слишком продвинуто на данный момент) и поток Scala: https://www.scala -lang.org / old / node / 10049.HTML

0 голосов
/ 24 октября 2018

Ваша путаница связана с разницей между variables и values.

Итак, когда вы делаете что-то вроде,

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

Тогда p2 - это мелкая копияp1, поэтому variables p1.firstname и p2.firstname указывают на один и тот же тип value типа String, который "amit".

Когда вы делаете p1.firstname = "raghu", выфактически говоря переменной p1.firstname указать на другой value типа String, который является "raghu".Здесь вы изменяете не само значение, а variable.

. Если вы измените само значение value, то и p1, и p2 будут отражать это изменение.К сожалению, значения 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))
...