2017-07-20 5 views
2

要素はすでにディープコピーを実装しています。2D MutableListをディープコピーする簡潔な方法は何ですか?

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

私はこの種のコードを使用していますが、冗長であるようです。 (あなたは間違いなく、ジェネリック医薬品がinvolved¹あるときそのウサギの穴に行きたくないとにより、JVMの型消去する)により型システムにおける制限のため、この問題は、型の安全性を迂回することなく、単一functonに一般化することはできません

+3

書く 'fは(a)の'のためのあなたのコピー動作が行うなし非常に冗長に見えます。 –

+0

@IngoKegelの意見では、インタフェースメソッドの名前がわずかに異なる場合、コードの目的(ディープコピー)はすぐには分かりません。 –

答えて

2

ただし、タイプセーフの問題では、ディメンション内のすべての増加のために前の関数に委譲、深い・コピー・パターンを実装する拡張機能のチェーンを書き込むことができます。

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

[1]:ジェネリック型キャストがList<Baz>からList<Foo>からキャストは常に、実行時にコンパイラによってでしょう実行されるため実行時には成功しますが、キャストされたリストにアクセスすると後で失敗します。前述の魔法の「単一機能」を実装することは可能ですが、わずかなエラーはクラスキャスト例外を使ってアクセスすると一見 "ランダム"にならない戻りデータ構造になります。

[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>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
+0

なぜあなたは自分自身を繰り返しましたか?シリアライズとデシリアライズは、Javaの深いコピーのためのものです。 –

+0

OPの最初の試行では、シリアライズが範囲外であるとわかりました。 –

0

java.lang.reflect.Array & java.lang.Cloneableを使用して単純なディープコピーの一例です。

NOETcloneメソッドは、このオブジェクトではなく、深いコピー操作の浅いコピーを実行しますが、例えば、深いコピー操作を提供するために、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 
    } 
} 
+0

OPが2D *リストをコピーするよう要求されていて、配列ではないことを考えれば、これが質問の範囲内にあるかどうかはわかりません。クローンと 'java.lang.reflect.Array'を持っていればObjectOutputStream-> ByteArrayOutputStream-> ByteArrayInputStream-> ObjectInputStreamでオブジェクトを直列化することもできますが、これはすべてのオブジェクトを強制的にシリアライズ可能にします。 –

+0

@ mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIuそれは今? –

関連する問題