深度复制 2D MutableList 的简洁方法是什么?
What is concise way of deep-copying a 2D MutableList?
该元素已经实现了深度复制。
fun <T : DeepCopiable> f(a: MutableList<MutableList<T>>) {
val copied = a.map { it.map { it.deepCopy() }.toMutableList() }.toMutableList()
...
}
我正在使用这种代码,但它看起来很冗长。
由于类型系统的限制,这个问题不能在不绕过类型安全的情况下推广到单个函数(并且由于 JVM 类型擦除,你绝对不想去 that 涉及泛型时的兔子洞¹)。
但是,您可以编写一个 链 扩展函数来实现深度复制模式,在类型安全的情况下,将维度的每次增加委托给前一个函数:
private typealias I<E> = Iterable<E>
private typealias Copy<E> = (E) -> E
private inline fun <T, R> I<T>.mapToMutable(transform: (T) -> R): I<R> = mapTo(mutableListOf(), transform)
fun <E> I<E>.deepCopy1(c: Copy<E>) = mapToMutable { c(it) }
fun <E> I<I<E>>.deepCopy2(c: Copy<E>) = mapToMutable { it.deepCopy1(c) }
fun <E> I<I<I<E>>>.deepCopy3(c: Copy<E>) = mapToMutable { it.deepCopy2(c) }
fun <E> I<I<I<I<E>>>>.deepCopy4(c: Copy<E>) = mapToMutable { it.deepCopy3(c) }
fun <E> I<I<I<I<I<E>>>>>.deepCopy5(c: Copy<E>) = mapToMutable { it.deepCopy4(c) }
由于 JVM 类型擦除,函数需要不同的名称(@JVMName
由于类型干扰歧义而无济于事²)。类型别名用于防止水平 space 爆炸³,并且函数集通过通用复制函数参数与深度可复制接口分离。
用法示例:
fun main(args: Array<String>) {
data class IntHolder(var value: Int)
val original = List(3) { a ->
List(3) { b ->
IntHolder(a + b)
}
}
val copied = original.deepCopy2 { it.copy() }
original[0][0].value = 18258125
println("original=$original")
println("copied =$copied")
}
->
original=[[IntHolder(value=18258125), IntHolder(value=1), IntHolder(value=2)], [IntHolder(value=1), IntHolder(value=2), IntHolder(value=3)], [IntHolder(value=2), IntHolder(value=3), IntHolder(value=4)]]
copied =[[IntHolder(value=0), IntHolder(value=1), IntHolder(value=2)], [IntHolder(value=1), IntHolder(value=2), IntHolder(value=3)], [IntHolder(value=2), IntHolder(value=3), IntHolder(value=4)]]
[1]:因为泛型类型转换是由编译器在运行时执行的,所以从 List<Foo>
到 List<Baz>
的转换在运行时总是会成功,但稍后在访问转换列表时会失败.实现上述魔法 "single function" 是可能的,但最轻微的错误都会导致返回的数据结构在访问时看似 "random" 失败,并出现 class 强制转换异常。
[2]:类型Iterable<Iterable<Foo>>
的值同时满足
fun <T> Iterable<T>.baz()
(T = Iterable<Foo>
) 和
fun <T> Iterable<Iterable<T>.baz()
(T = Foo
)
因此,如果链中的所有方法都具有相同的函数名称,但 JVM 名称不同,编译器将无法确定要使用的正确方法。
[3]:
Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<ithinkyougetthepoint>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
这是一个简单的深度复制示例,使用 java.lang.reflect.Array & java.lang.Cloneable。
Noet:clone method performs a shallow copy of this object, not a deep copy operation, but you can override the clone方法提供了deep复制操作,例如:
val list = mutableListOf(mutableListOf(arrayOf(1)))
val copied = list.deepCopy()
println(copied !== list) //true: not the same
println(copied.map{it.map{it.toList()}} == list.map{it.map{it.toList()}})
// ^---true: content equals
// v--- Array is cloned, since it has implemented Cloneable
println(copied[0][0] !== array[0][0]) // true
typealias NativeArray = java.lang.reflect.Array
@Suppress("UNCHECKED_CAST")
fun <T> T.deepCopy(): T {
return when (this) {
is Array<*> -> {
val type = this.javaClass.componentType
NativeArray.newInstance(type, size).also {
this.forEachIndexed { i, item ->
NativeArray.set(it, i, item.deepCopy())
}
} as T
}
is MutableList<*> -> this.mapTo(mutableListOf()) { it.deepCopy() } as T
is List<*> -> this.map { it.deepCopy() } as T
is Cloneable -> this.javaClass.getDeclaredMethod("clone").let {
it.isAccessible = true;
it.invoke(this) as T
}
else -> this
}
}
该元素已经实现了深度复制。
fun <T : DeepCopiable> f(a: MutableList<MutableList<T>>) {
val copied = a.map { it.map { it.deepCopy() }.toMutableList() }.toMutableList()
...
}
我正在使用这种代码,但它看起来很冗长。
由于类型系统的限制,这个问题不能在不绕过类型安全的情况下推广到单个函数(并且由于 JVM 类型擦除,你绝对不想去 that 涉及泛型时的兔子洞¹)。
但是,您可以编写一个 链 扩展函数来实现深度复制模式,在类型安全的情况下,将维度的每次增加委托给前一个函数:
private typealias I<E> = Iterable<E>
private typealias Copy<E> = (E) -> E
private inline fun <T, R> I<T>.mapToMutable(transform: (T) -> R): I<R> = mapTo(mutableListOf(), transform)
fun <E> I<E>.deepCopy1(c: Copy<E>) = mapToMutable { c(it) }
fun <E> I<I<E>>.deepCopy2(c: Copy<E>) = mapToMutable { it.deepCopy1(c) }
fun <E> I<I<I<E>>>.deepCopy3(c: Copy<E>) = mapToMutable { it.deepCopy2(c) }
fun <E> I<I<I<I<E>>>>.deepCopy4(c: Copy<E>) = mapToMutable { it.deepCopy3(c) }
fun <E> I<I<I<I<I<E>>>>>.deepCopy5(c: Copy<E>) = mapToMutable { it.deepCopy4(c) }
由于 JVM 类型擦除,函数需要不同的名称(@JVMName
由于类型干扰歧义而无济于事²)。类型别名用于防止水平 space 爆炸³,并且函数集通过通用复制函数参数与深度可复制接口分离。
用法示例:
fun main(args: Array<String>) {
data class IntHolder(var value: Int)
val original = List(3) { a ->
List(3) { b ->
IntHolder(a + b)
}
}
val copied = original.deepCopy2 { it.copy() }
original[0][0].value = 18258125
println("original=$original")
println("copied =$copied")
}
->
original=[[IntHolder(value=18258125), IntHolder(value=1), IntHolder(value=2)], [IntHolder(value=1), IntHolder(value=2), IntHolder(value=3)], [IntHolder(value=2), IntHolder(value=3), IntHolder(value=4)]]
copied =[[IntHolder(value=0), IntHolder(value=1), IntHolder(value=2)], [IntHolder(value=1), IntHolder(value=2), IntHolder(value=3)], [IntHolder(value=2), IntHolder(value=3), IntHolder(value=4)]]
[1]:因为泛型类型转换是由编译器在运行时执行的,所以从 List<Foo>
到 List<Baz>
的转换在运行时总是会成功,但稍后在访问转换列表时会失败.实现上述魔法 "single function" 是可能的,但最轻微的错误都会导致返回的数据结构在访问时看似 "random" 失败,并出现 class 强制转换异常。
[2]:类型Iterable<Iterable<Foo>>
的值同时满足
fun <T> Iterable<T>.baz()
(T = Iterable<Foo>
) 和
fun <T> Iterable<Iterable<T>.baz()
(T = Foo
)
因此,如果链中的所有方法都具有相同的函数名称,但 JVM 名称不同,编译器将无法确定要使用的正确方法。
[3]:
Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<Iterable<ithinkyougetthepoint>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
这是一个简单的深度复制示例,使用 java.lang.reflect.Array & java.lang.Cloneable。
Noet:clone method performs a shallow copy of this object, not a deep copy operation, but you can override the clone方法提供了deep复制操作,例如:
val list = mutableListOf(mutableListOf(arrayOf(1)))
val copied = list.deepCopy()
println(copied !== list) //true: not the same
println(copied.map{it.map{it.toList()}} == list.map{it.map{it.toList()}})
// ^---true: content equals
// v--- Array is cloned, since it has implemented Cloneable
println(copied[0][0] !== array[0][0]) // true
typealias NativeArray = java.lang.reflect.Array
@Suppress("UNCHECKED_CAST")
fun <T> T.deepCopy(): T {
return when (this) {
is Array<*> -> {
val type = this.javaClass.componentType
NativeArray.newInstance(type, size).also {
this.forEachIndexed { i, item ->
NativeArray.set(it, i, item.deepCopy())
}
} as T
}
is MutableList<*> -> this.mapTo(mutableListOf()) { it.deepCopy() } as T
is List<*> -> this.map { it.deepCopy() } as T
is Cloneable -> this.javaClass.getDeclaredMethod("clone").let {
it.isAccessible = true;
it.invoke(this) as T
}
else -> this
}
}