2017-11-17 2455 views
3

有人可以解釋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:美孚(α= 5,條=欄(X = 0),則列表= [1,2,3])
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:酒吧(X = 0)

爲什麼barCopy.x=0(預期),但fooCopy.bar.x=2(我認爲這將是0)。由於Bar也是一個數據類,所以當foo.copy()執行時,我預計foo.bar也是一個副本。

要深拷貝所有成員,我可以做這樣的事情:

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

fooCopy:美孚(α= 5,條=欄(X = 0),則列表= [1,2, 3])

但是我錯過了什麼或有沒有更好的方法來做到這一點,而無需指定這些成員需要強制深度複製?

回答

8

Kotlin的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) 
1

正如@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)