如何将Item结构和所有指针复制到新结构?
type Item struct { A []*ASet `json:"a,omitempty"` B []*BSet. `json:"b,omitempty"` C []*CSet. `json:"c,omitempty"` } type ASet struct { UID string `json:"uid,omitempty"` Items []*ItemA `json:"member,omitempty"` } type ItemA struct { UID string `json:"uid,omitempty"` Portset []*PortSet `json:"portset,omitempty"` } type PortSet struct { UID string `json:"uid,omitempty"` Ports []*Port `json:"member,omitempty"` } type Port struct { UID string `json:"uid,omitempty"` Port int `json:"port,omitempty"` }
我不希望新结构引用旧结构。
本质上您想要的是标准库不支持的深层副本。
您的选择:
“手动”执行复制,例如,创建新的结构并复制字段,其中必须以递归方式手动复制指针或切片/地图/通道/等。 通过将您的结构分配给另一个可复制所有字段的结构,这是最容易做到的,因此,您基本上只需要培养指针/地图/切片等(但需要递归)。
使用外部库,例如github.com/mohae/deepcopy,github.com/ulule/deepcopier或github.com/mitchellh/copystructure
github.com/mohae/deepcopy
github.com/ulule/deepcopier
github.com/mitchellh/copystructure
最后一个选项可能如下所示:
var i1 Item data, err := json.Marshal(i1) if err != nil { panic(err) } var i2 Item if err := json.Unmarshal(data, &i2); err != nil { panic(err) } // i2 holds a deep copy of i1
请注意,封送/取消封送并不是特别有效,而是简单而紧凑的。还要注意,这可能无法很好地处理递归数据结构,甚至可能挂起或出现紧急情况(例如,字段指向包含的结构),但是处理递归结构可能是所有解决方案的问题。另请注意,这不会克隆未导出的字段。
关于封送处理/取消封送处理的好处是,您可以轻松创建一个辅助函数来深度复制“ any”值:
func deepCopy(v interface{}) (interface{}, error) { data, err := json.Marshal(v) if err != nil { return nil, err } vptr := reflect.New(reflect.TypeOf(v)) err = json.Unmarshal(data, vptr.Interface()) if err != nil { return nil, err } return vptr.Elem().Interface(), err }
测试它:
p1 := image.Point{X: 1, Y: 2} fmt.Printf("p1 %T %+v\n", p1, p1) p2, err := deepCopy(p1) if err != nil { panic(err) } p1.X = 11 fmt.Printf("p1 %T %+v\n", p1, p1) fmt.Printf("p2 %T %+v\n", p2, p2)
输出(在Go Playground上尝试):
p1 image.Point (1,2) p1 image.Point (11,2) p2 image.Point (1,2)