2012-10-31 42 views
10

Tôi có thể sao chép sâu bản đồ bản đồ trong Groovy như thế nào? Các khóa bản đồ là Strings hoặc Ints. Các giá trị là Strings, Primitive Objects hoặc các bản đồ khác, theo cách đệ quy.Bản đồ sâu Bản đồ trong Groovy

Trả lời

21

Một cách dễ dàng là thế này:

// 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() 
} 
+0

Tuyệt vời. Tôi đang sử dụng điều này để sao chép sâu một ConfigObject groovy như clone() chỉ làm một bản sao nông. Bản sao nông không đủ trên một ConfigObject cho các nhu cầu của tôi. Cảm ơn. – noumenon

+0

Điều này là khá tuyệt vời –

+0

Gonna phải nhớ điều này! –

2

Tôi sợ bạn phải thực hiện theo cách clone. Bạn có thể cung cấp cho Apache Commons Lang SerializationUtils một thử

+0

Tôi khá mới mẻ đối với Groovy. Tôi có thể sai. –

+0

Bản sao dường như hoạt động tốt với bản đồ. Nhưng ngay khi bạn mang những vật thể phức tạp hơn vào cảnh, nó cũng không hoạt động, bởi vì nó là một bản sao nông. Bản sao sâu của Ayman là nhanh và hoạt động cho các đối tượng mà tôi đã thử (bao gồm cả ConfigObject). – noumenon

4

Tôi vừa mới trúng vấn đề này là tốt, và tôi chỉ tìm thấy:

deepCopy = evaluate(original.inspect()) 

Mặc dù tôi đã được mã hóa trong Groovy trong ít hơn 12 giờ, tôi tự hỏi nếu có thể có một số vấn đề đáng tin cậy với việc sử dụng evaluate. Ngoài ra, ở trên không xử lý các dấu gạch chéo ngược. Điều này:

deepCopy = evaluate(original.inspect().replace('\\','\\\\')) 

.

+0

Cảm ơn bạn đã đề cập đến việc kiểm tra. Tôi đã tìm kiếm các lứa tuổi cho một tương đương Groovy của repr của Python! Để nghĩ rằng nó đã có tất cả cùng ... – Tobia

+1

Làm việc cho tôi khi chỉnh sửa docker-compose.yml với groovy và jenkins. Cảm ơn! (đã thêm nhận xét này để tìm kiếm google dễ dàng hơn) –

3

Để đi sâu về sao chép từng thành viên trong một lớp, newInstance() tồn tại cho các đối tượng Lớp. Ví dụ:

foo = ["foo": 1, "bar": 2] 
bar = foo.getClass().newInstance(foo) 
foo["foo"] = 3 
assert(bar["foo"] == 1) 
assert(foo["foo"] == 3) 

Xem http://groovy-lang.org/gdk.html và điều hướng đến java.lang, Class và cuối cùng là quá tải phương thức mớiInstance.

CẬP NHẬT:

Ví dụ tôi có ở trên là cuối cùng một ví dụ về một bản sao cạn, nhưng những gì tôi thực sự có nghĩa là nói chung, bạn hầu như luôn luôn phải xác định riêng đáng tin cậy Logic bản sao sâu của bạn, với có lẽ sử dụng phương thức newInstance(), nếu phương thức clone() là không đủ. Dưới đây là một số cách để thực hiện điều đó:

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) 

Tôi đã sử dụng @Canonical cho phương thức equals() và tuple ctor. Xem groovy doc Chapter 3.4.2, Code Generation Transformations.

Một cách khác để thực hiện sao chép sâu là sử dụng mixin. Hãy nói rằng bạn muốn một lớp hiện có để có chức năng sao chép sâu:

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

Hoặc loại (một lần nữa thấy groovy doc) nếu bạn muốn ngữ nghĩa sao chép sâu dựa trên một số loại bối cảnh thời gian chạy:

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 
Các vấn đề liên quan