Quelqu'un pourrait-il expliquer comment fonctionne exactement la méthode copy
pour les classes de données Kotlin? Il semble que pour certains membres, une copie (profonde) n’est pas créée et les références sont toujours à l’original.
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)
Sortie:
foo: Foo (a = 5, barre = barre (x = 0), liste = [1, 2, 3])
foo: Foo (a = 10, barre = barre (x = 2), liste = [1, 2, 3, 4])
fooCopy: Foo (a = 5, barre = barre (x = 2), liste = [1, 2, 3, 4])
barCopy: Barre (x = 0)
Pourquoi barCopy.x=0
(attendu), mais fooCopy.bar.x=2
(je pense que ce serait 0). Puisque Bar
est également une classe de données, je m'attendrais à ce que foo.bar
soit également une copie lorsque foo.copy()
est exécuté.
Pour copier en profondeur tous les membres, je peux faire quelque chose comme ceci:
val fooCopy = foo.copy(bar = foo.bar.copy(), list = foo.list.toMutableList())
fooCopy: Foo (a = 5, barre = barre (x = 0), liste = [1, 2, 3])
Mais manque-t-il quelque chose ou existe-t-il un meilleur moyen de le faire sans avoir à préciser que ces membres doivent forcer une copie conforme?
La méthode copy
de Kotlin n'est pas censée être une copie profonde. Comme expliqué dans la documentation de référence ( https://kotlinlang.org/docs/reference/data-classes.html ), pour une classe telle que:
data class User(val name: String = "", val age: Int = 0)
la mise en œuvre copy
serait:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Donc, comme vous pouvez le voir, c'est une copie superficielle. Les implémentations de copy
dans vos cas spécifiques seraient:
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)
Comme @Ekeko l'a dit, la fonction copy()
implémentée pour la classe de données est une copie superficielle qui ressemble à ceci:
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list)
Pour effectuer une copie en profondeur, vous devez remplacer la fonction copy()
.
fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list)
Il existe un moyen de copier en profondeur un objet dans Kotlin (et Java): sérialisez-le en mémoire, puis désérialisez-le en un nouvel objet. Cela ne fonctionnera que si toutes les données contenues dans l'objet sont des primitives ou implémentent l'interface Serializable.
Voici une explication avec un exemple de code Kotlin https://rosettacode.org/wiki/Deepcopy#Kotlin
Remarque: cette solution devrait également s'appliquer à Android en utilisant l'interface Parcelable au lieu de Serializable. Colisable est plus efficace.