有人能解释一下静态编程语言数据类的copy
方法是如何工作的吗?对于一些成员来说,似乎没有真正创建(深度)副本,并且引用仍然是原始的。
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])
foCopy:Foo(a=5,bar=Bar(x=2),list=[1,2,3,4])
bar Copy: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())
foCopy:Foo(a=5,bar=Bar(x=0),list=[1,2,3])
但是我遗漏了什么,或者有没有更好的方法来做到这一点,而不需要指定这些成员需要强制深拷贝?
静态编程语言的copy
方法根本不应该是深度副本。如参考文档(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)
当心那些只是将列表引用从旧对象复制到新对象的答案。深度复制的一种快速方法(虽然不是很有效)是序列化/反序列化对象,即将对象转换为JSON,然后将它们转换回POJO。如果你使用的是GSON,这里有一段快速代码:
class Foo {
fun deepCopy() : Foo {
return Gson().fromJson(Gson().toJson(this), this.javaClass)
}
}
正如@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)