如何复制结构并取消引用所有指针
How to copy struct and dereference all pointers
如何复制 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"`
}
我不希望新结构引用旧结构。
你想要的本质上是标准库不支持的深拷贝。
您的选择:
- 复制 "manually",例如创建一个新结构并复制字段,其中必须以递归方式手动复制指针或 slices/maps/channels/etc。
最简单的方法是将您的结构分配给另一个复制所有字段的结构,因此您基本上只需要培养 pointers/maps/slices 等(但递归)。
- 使用外部库,例如
github.com/mohae/deepcopy
, github.com/ulule/deepcopier
or github.com/mitchellh/copystructure
- 将您的结构编组为某种格式(例如 JSON),然后解编为另一个变量。
最后一个选项可能如下所示:
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
请注意,marshaling/unmarshaling 不是特别有效,但简单紧凑。另请注意,这可能无法很好地处理递归数据结构,甚至可能挂起或崩溃(例如,字段指向包含结构),但处理递归结构可能是所有解决方案的问题。另请注意,这不会克隆未导出的字段。
这种编组/解组的好处是您可以轻松创建辅助函数来深度复制 "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)
如何复制 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"`
}
我不希望新结构引用旧结构。
你想要的本质上是标准库不支持的深拷贝。
您的选择:
- 复制 "manually",例如创建一个新结构并复制字段,其中必须以递归方式手动复制指针或 slices/maps/channels/etc。
最简单的方法是将您的结构分配给另一个复制所有字段的结构,因此您基本上只需要培养 pointers/maps/slices 等(但递归)。 - 使用外部库,例如
github.com/mohae/deepcopy
,github.com/ulule/deepcopier
orgithub.com/mitchellh/copystructure
- 将您的结构编组为某种格式(例如 JSON),然后解编为另一个变量。
最后一个选项可能如下所示:
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
请注意,marshaling/unmarshaling 不是特别有效,但简单紧凑。另请注意,这可能无法很好地处理递归数据结构,甚至可能挂起或崩溃(例如,字段指向包含结构),但处理递归结构可能是所有解决方案的问题。另请注意,这不会克隆未导出的字段。
这种编组/解组的好处是您可以轻松创建辅助函数来深度复制 "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)