代码之家  ›  专栏  ›  技术社区  ›  Naetmul

深度复制2D可变列表的简明方法是什么?

  •  3
  • Naetmul  · 技术社区  · 8 年前

    fun <T : DeepCopiable> f(a: MutableList<MutableList<T>>) {
        val copied = a.map { it.map { it.deepCopy() }.toMutableList() }.toMutableList()
        ...
    }
    

    我正在使用这种代码,但它似乎很冗长。

    2 回复  |  直到 8 年前
        1
  •  3
  •   F. George    8 年前

    由于类型系统中的限制,如果不绕过类型安全性(并且由于JVM类型擦除,您肯定不想去),这个问题就不能推广到单个functon 那个 兔子洞(当涉及泛型时)。

    但是,您可以编写一个

    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 由于类型干扰模糊,没有帮助)。类型别名用于防止水平空间爆炸,函数集通过通用复制函数参数与深度可复制接口解耦。

    示例用法:

    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)]]
    

    List<Foo> List<Baz> 将始终在运行时成功,但在稍后访问浇铸列表时失败。实现上述神奇的“单个函数”是可能的,但只要有一点点错误,就会导致返回的数据结构在访问时出现类转换异常,看起来是“随机”的。

    [2] :类型的值 Iterable<Iterable<Foo>>

    fun <T> Iterable<T>.baz() (T)= Iterable<Foo>
    fun <T> Iterable<Iterable<T>.baz() Foo )

    因此,如果链中的所有方法具有相同的函数名,但JVM名称不同,则编译器将无法确定要使用的正确方法。

    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>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
        2
  •  0
  •   holi-java    8 年前

    下面是一个简单的深度复制示例,使用 java.lang.reflect.Array & java.lang.Cloneable .

    诺特 clone 浅的 此对象的副本,而不是 深的 克隆 深的

    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
        }
    }