Groovy中的深拷贝映射

Aym*_*man 23 groovy deep-copy

如何在Groovy中深层复制地图地图?字符键是字符串或Ints.值以字符串,原始对象或其他映射,以递归方式.

Aym*_*man 29

一个简单的方法是:

// standard deep copy implementation
def deepcopy(orig) {
     bos = new ByteArrayOutputStream()
     oos = new ObjectOutputStream(bos)
     oos.writeObject(orig); oos.flush()
     bin = new ByteArrayInputStream(bos.toByteArray())
     ois = new ObjectInputStream(bin)
     return ois.readObject()
}
Run Code Online (Sandbox Code Playgroud)

  • 这对Json也不起作用。`java.io.NotSerializableException:groovy.json.internal.LazyMap` (2认同)

Kor*_*lak 10

对于 Json (LazyMap),这对我来说很重要

copyOfMap = new HashMap<>()
originalMap.each { k, v -> copyOfMap.put(k, v) }
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(copyOfMap))
Run Code Online (Sandbox Code Playgroud)

编辑:简化:Ed Randall

copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(originalMap))
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是对已接受答案的更简单的序列化。但是第 1 行和第 2 行肯定是多余的,您只需要一行:```copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(originalMap))``` (2认同)

Sla*_*agh 7

我刚刚遇到这个问题,我刚刚发现:

deepCopy = evaluate(original.inspect())
Run Code Online (Sandbox Code Playgroud)

虽然我已经在Groovy编写了不到12个小时的编码,但我想知道使用时是否存在一些信任问题evaluate.此外,以上不处理反斜杠.这个:

deepCopy = evaluate(original.inspect().replace('\\','\\\\'))
Run Code Online (Sandbox Code Playgroud)

确实.

  • 使用groovy和jenkins编辑docker-compose.yml时为我工作。谢谢!(添加了此评论,以简化Google搜索) (2认同)

sol*_*333 7

为了深入复制类中的每个成员,存在Class对象的newInstance()。例如,

foo = ["foo": 1, "bar": 2]
bar = foo.getClass().newInstance(foo)
foo["foo"] = 3
assert(bar["foo"] == 1)
assert(foo["foo"] == 3)
Run Code Online (Sandbox Code Playgroud)

请参阅http://groovy-lang.org/gdk.html并导航到java.lang,Class,最后是newInstance方法重载。

更新

我上面的示例最终只是一个浅表副本的示例,但是我真正的意思是,通常来说,如果clone(( )方法还不够。这是几种解决方法:

import groovy.transform.Canonical
import groovy.transform.AutoClone
import static groovy.transform.AutoCloneStyle.*

// in @AutoClone, generally the semantics are
//  1. clone() is called if property implements Cloneable else,
//  2. initialize property with assignment, IOW copy by reference
//
// @AutoClone default is to call super.clone() then clone() on each property.
//
// @AutoClone(style=COPY_CONSTRUCTOR) which will call the copy ctor in a 
//  clone() method. Use if you have final members.
//
// @AutoClone(style=SIMPLE) will call no arg ctor then set the properties
//
// @AutoClone(style=SERIALIZATION) class must implement Serializable or 
//  Externalizable. Fields cannot be final. Immutable classes are cloned.
//  Generally slower.
//
// if you need reliable deep copying, define your own clone() method

def assert_diffs(a, b) {
    assert a == b // equal objects
    assert ! a.is(b) // not the same reference/identity
    assert ! a.s.is(b.s) // String deep copy
    assert ! a.i.is(b.i) // Integer deep copy
    assert ! a.l.is(b.l) // non-identical list member
    assert ! a.l[0].is(b.l[0]) // list element deep copy
    assert ! a.m.is(b.m) // non-identical map member
    assert ! a.m['mu'].is(b.m['mu']) // map element deep copy
}

// deep copy using serialization with @AutoClone 
@Canonical
@AutoClone(style=SERIALIZATION)
class Bar implements Serializable {
   String s
   Integer i
   def l = []
   def m = [:]

   // if you need special serialization/deserialization logic override
   // writeObject() and/or readObject() in class implementing Serializable:
   //
   // private void writeObject(ObjectOutputStream oos) throws IOException {
   //    oos.writeObject(s) 
   //    oos.writeObject(i) 
   //    oos.writeObject(l) 
   //    oos.writeObject(m) 
   // }
   //
   // private void readObject(ObjectInputStream ois) 
   //    throws IOException, ClassNotFoundException {
   //    s = ois.readObject()
   //    i = ois.readObject()
   //    l = ois.readObject()
   //    m = ois.readObject()
   // }
}

// deep copy by using default @AutoClone semantics and overriding 
// clone() method
@Canonical
@AutoClone
class Baz {
   String s
   Integer i
   def l = []
   def m = [:]

   def clone() {
      def cp = super.clone()
      cp.s = s.class.newInstance(s)
      cp.i = i.class.newInstance(i)
      cp.l = cp.l.collect { it.getClass().newInstance(it) }
      cp.m = cp.m.collectEntries { k, v -> 
         [k.getClass().newInstance(k), v.getClass().newInstance(v)] 
      }
      cp
   }
}

// assert differences
def a = new Bar("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
def b = a.clone()
assert_diffs(a, b)

a = new Baz("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
b = a.clone()
assert_diffs(a, b)
Run Code Online (Sandbox Code Playgroud)

我用于@Canonicalequals()方法和元组ctor。请参阅groovy doc第3.4.2章,代码生成转换

进行深度复制的另一种方法是使用mixins。假设您希望现有的类具有深层复制功能:

class LinkedHashMapDeepCopy {
   def deep_copy() {
      collectEntries { k, v -> 
         [k.getClass().newInstance(k), v.getClass().newInstance(v)]
      }
   }
}

class ArrayListDeepCopy {
   def deep_copy() {
      collect { it.getClass().newInstance(it) }
   } 
}

LinkedHashMap.mixin(LinkedHashMapDeepCopy)
ArrayList.mixin(ArrayListDeepCopy)

def foo = [foo: 1, bar: 2]
def bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo['foo'].is(bar['foo'])

foo = ['foo', 'bar']
bar = foo.deep_copy() 
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0])
Run Code Online (Sandbox Code Playgroud)

或类别(再次参见groovy doc),如果您想基于某种运行时上下文进行深度复制语义:

import groovy.lang.Category

@Category(ArrayList)
class ArrayListDeepCopy {
   def clone() {
      collect { it.getClass().newInstance(it) }
   } 
}

use(ArrayListDeepCopy) {
   def foo = ['foo', 'bar']
   def bar = foo.clone() 
   assert foo == bar
   assert ! foo.is(bar)
   assert ! foo[0].is(bar[0]) // deep copying semantics
}

def foo = ['foo', 'bar']
def bar = foo.clone() 
assert foo == bar
assert ! foo.is(bar)
assert foo[0].is(bar[0]) // back to shallow clone
Run Code Online (Sandbox Code Playgroud)


Aru*_*nan 6

恐怕你必须这样做clone。您可以尝试一下Apache Commons Lang SerializationUtils