Метод копирования класса данных Kotlin не выполняет глубокое копирование всех членов

Может ли кто-нибудь объяснить, как именно работает метод copy для классов данных Kotlin? Кажется, что для некоторых участников, (глубокая) копия на самом деле не создана, а ссылки по-прежнему принадлежат оригиналу.

 fun test() { val bar = Bar(0) val foo = Foo(5, bar, mutableListOf(1, 2, 3)) println("foo : $foo") val barCopy = bar.copy() val fooCopy = foo.copy() foo.a = 10 bar.x = 2 foo.list.add(4) println("foo : $foo") println("fooCopy: $fooCopy") println("barCopy: $barCopy") } data class Foo(var a: Int, val bar: Bar, val list: MutableList<Int> = mutableListOf()) data class Bar(var x: Int = 0) 

Вывод:
foo: Foo (a = 5, bar = Bar (x = 0), list = [1, 2, 3])
foo: Foo (a = 10, bar = Bar (x = 2), list = [1, 2, 3, 4])
fooCopy: Foo (a = 5, bar = Bar (x = 2), list = [1, 2, 3, 4])
barCopy: Bar (x = 0)

Почему barCopy.x=0 (ожидается), но fooCopy.bar.x=2 (я бы подумал, что это будет 0). Поскольку Bar также является классом данных, я бы ожидал, что foo.bar также будет копией при выполнении foo.copy() .

Чтобы глубоко скопировать всех участников, я могу сделать что-то вроде этого:

 val fooCopy = foo.copy(bar = foo.bar.copy(), list = foo.list.toMutableList()) 

fooCopy: Foo (a = 5, bar = Bar (x = 0), list = [1, 2, 3])

Но я что-то упускаю, или есть лучший способ сделать это, не указывая, что этим членам нужно заставить глубокую копию?

Метод copy Kotlin не должен быть глубокой копией вообще. Как поясняется в справочном документе ( https://kotlinlang.org/docs/reference/data-classes.html ), для класса, такого как:

 data class User(val name: String = "", val age: Int = 0) 

реализация copy будет:

 fun copy(name: String = this.name, age: Int = this.age) = User(name, age) 

Итак, как вы можете видеть, это мелкая копия. Реализация copy в ваших конкретных случаях будет:

 fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list) = Foo(a, bar, list) fun copy(x: Int = this.x) = Bar(x) 

Как сказал @Ekeko, функция copy() по умолчанию, реализованная для класса данных, представляет собой мелкую копию, которая выглядит так:

 fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list) 

Чтобы выполнить глубокую копию, вы должны переопределить функцию copy() .

 fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list) 
Intereting Posts
Ошибка – невозможно изменить заголовок supportActionBar Как использовать rxjava2 с модификацией в android Ошибка ': android: transformKotlinClassesWithJillForDebug'. При создании приложения для Android, написанного в Kotlin + LibGDX Как я могу реплицировать несколько первичных конструкторов? Разница между Lock.withLock и синхронизация в Kotlin Kotlin: Как асинхронно ждать список одинаковых методов? Android Kotlin Extension – супер-вызов Теперь отображается плавающая кнопка действия Переопределить метод Java со сложным типом в Котлине Переопределяя метод Java @Nullable varargs в Котлине, IDE жалуется, что он ничего не отменяет Наблюдение за повторным использованием выполнения оператора Firebase Firestore как перечислить авторизованные документы? Android – Check for Not Null не работает как ожидается Перегруженные методы, получающие функции более высокого порядка в Котлине Как использовать код, который опирается на ThreadLocal с сопрограммами Kotlin