在Golang中深度复制数据结构 [英] Deep copying data structures in golang

查看:257
本文介绍了在Golang中深度复制数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想复制一个数据结构的实例。由于go没有任何内置函数,因此我正在使用第三方库: https://github.com/emirpasic/gods

I want to duplicate an instance of a data structure. Since go does not have any builtins, I am using a third party library: https://github.com/emirpasic/gods.

例如,我可以尝试使用具有哈希集的深度复制。

For example, I may try use deep copy with a hash set.

var c, d hashset.Set
c = *hashset.New()
c.Add(1)
deepcopy.Copy(d, c)
c.Add(2)
fmt.Println(c.Contains(2))
fmt.Println(d.Contains(2))
fmt.Println(c.Contains(1))
fmt.Println(d.Contains(1))

但是,哈希集的内容根本不会被复制。我知道深度复制模块无法复制未导出的值,但是由于库中没有内置的复制构造函数,是否就意味着在不修改其代码的情况下无法与该库完全复制数据结构实例? (类似的问题发生在我研究过的其他一些库中。)

However, the content of the hash set is not copied at all. I know deep copy modules can't copy unexported values, but since there is no builtin "copy constructor" in the library, does it mean it is not possible to fully duplicate a data structure instance with the library without modifying its code? (Similar problem happens with some other libraries I looked into).

我是golang的新手,感觉不对,因为类似的事情很容易实现,例如在C ++中。我知道我可以编写自己的版本或修改其代码,但是这比预期的工作量大,因此我认为应该采用惯用的方式。

I am new to golang and does not feel right, since similar things can be easily achieved for example in C++. I know I could write my own version or modify their code, but it is too much work than expected and that's why I think there should be an idiomatic way.

PS:对于可能会说不需要这种功能的人,我正在将一些具有某些数据结构的复杂状态分配给并行计算线程,他们直接使用这些状态,并且不得互相干扰。

PS: For people who may say "there is no need of such functionality", I am distributing some complex state with some data structures to parallel calculation threads, they use the states directly and must not interfere with each other.

推荐答案

不幸的是,在Go中无法做到这一点。我想到的第一个工具是反射(包 reflect ),但使用反射只能读取未导出的字段,但不能设置它们。请参见如何克隆具有未导出字段的结构?

Unfortunately or not, there is no way to do this in Go. First tool that comes to mind is reflection (package reflect), but using reflection you can only read unexported fields, but you can't set them. See How to clone a structure with unexported field?

克隆具有未导出字段的结构的唯一方法是使用包 不安全 (在此处查看示例:在golang / reflect中访问未导出的字段?),但顾名思义,这是不安全,您应尽可能远离它。使用不安全创建的程序不能保证它们继续与较新的Go版本一起使用,或者不能在每个平台上都具有相同的行为。

The only way to clone structures with unexported fields would be to use package unsafe (see an example here: Access unexported fields in golang/reflect?), but as its name says: it's unsafe and you should stay away from it as much as possible. Programs created using unsafe has no guarantee that they continue to work with newer Go releases, or that they behave the same on every platform.

通常在Go中支持克隆的唯一正确方法是程序包本身是否支持此类操作。

In general the only and proper way to support cloning in Go is if the package itself supports such operations.

注意#1:

这并不意味着在某些特定情况下,您无法通过创建来模仿克隆一个新值并手动建立其状态。例如,您可以通过创建新地图,遍历原始地图的键值对并将其设置在新地图中来克隆地图

This does not mean that in some specific case you can't "mimic" cloning by creating a new value and building its state manually. For example you can clone a map by creating a new map, iterating over the key-value pairs of the original and setting them in the new map.

注意#2:

请注意,您可以对具有未导出字段的结构进行精确复制只需将它们分配到另一个结构变量(相同类型)即可,该变量将正确地复制

Do note that you can make "exact" copies of structs having unexported fields by simply assigning them to another struct variable (of the same type), which will properly copy the unexported fields too.

在此示例中:

type person struct {
    Name string
    age  *int
}

age := 22
p := &person{"Bob", &age}
fmt.Println(p)

p2 := new(person)
*p2 = *p
fmt.Println(p2)

将输出(在去游乐场):

&{Bob 0x414020}
&{Bob 0x414020}

我们甚至可以使用 reflect 而不依赖于具体类型:

Which we can even generalize using reflect without relying on the concrete type:

type person struct {
    Name string
    age  *int
}

age := 22
p := &person{"Bob", &age}
fmt.Println(p)

v := reflect.ValueOf(p).Elem()
vp2 := reflect.New(v.Type())
vp2.Elem().Set(v)
fmt.Println(vp2)

去游乐场

但是我们不能做 >将未导出的 person.age 字段更改为指向其他内容。没有声明包的帮助,它只能是 nil 或相同的指针值(指向对象的原始字段)。

But what we can't do is change the person.age unexported field to point to something else. Without help of the declaring package, it can only be nil or the same pointer value (pointing to the object as the original field).

另请参阅相关内容:在golang中深度复制对象的更快方法

这篇关于在Golang中深度复制数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆