duandingcu7010
2019-05-29 07:29
浏览 492
已采纳

在Golang中深度复制数据结构

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

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: 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.

图片转代码服务由CSDN问答提供 功能建议

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

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

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

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

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

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

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • doujianguang5506 2019-05-29 08:02
    已采纳

    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?

    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.

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

    Note #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.

    Note #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.

    Like in this example:

    type person struct {
        Name string
        age  *int
    }
    
    age := 22
    p := &person{"Bob", &age}
    fmt.Println(p)
    
    p2 := new(person)
    *p2 = *p
    fmt.Println(p2)
    

    Which will output (try it on the Go Playground):

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

    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)
    

    Try this one on the Go Playground.

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

    Also see related: Quicker way to deepcopy objects in golang

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • doqo89924 2019-05-29 08:02

    If the package your are using does not provide a copy function for the data stucture, then I would write my own type-safe copy function. Moreover, I would not worry about unexported fields, because there must be a reason why the developer has decided to hide those fields to users.

    In your example:

    func NewHashSetCopy(src *hashset.Set) *hashset.Set{
        dst := *hashset.New()
        iterator := src.Iter()
        for elem := range iterator {
            dst.Add(elem)
        }
        return dst
    }
    
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题