深拷贝之循环引用
Table of Contents
题目⌗
实现如下结构体的深拷贝。
type Node struct {
Data int
Fields []*Node
}
即指针指向的内存也需要Copy一份。
解析⌗
观察结构体,由于Fields字段里存放的是指向Node结构体的指针切片,深拷贝时要考虑循环引用的问题,如:
struct a :
data: 1
fields: b, c
struct b:
data: 2
fields: c
struct c:
data: 3
fields: a // 这里循环引用了a, c->a->b, c->a
可以考虑使用map[*Node]*Node
来判断是否有环的情况,即用map[src] = dst
来保存拷贝过的节点。
代码⌗
代码如下:
package main
import (
"go/ast"
"go/token"
)
type Node struct {
Data int
Fields []*Node
}
// deep copy
var M map[*Node]*Node
func Dup(src *Node) *Node {
if src == nil {
return nil
}
node := &Node{
Data: src.Data,
Fields: nil,
}
M[src] = node
fields := []*Node{}//make([]*Node, len(src.Fields))
for i:=0;i<len(src.Fields);i++ {
var tmp *Node
if src.Fields[i] != nil {
// if exist, is loop
if addr, ok := M[src.Fields[i]]; ok {
tmp = addr
} else {
tmp = Dup(src.Fields[i])
}
}
if tmp != nil {
fields = append(fields, tmp)
}
}
node.Fields = fields
return node
}
func main() {
M = make(map[*Node]*Node)
a1 := &Node{
Data: 1,
Fields: nil,
}
a2 := &Node{
Data: 2,
Fields: nil,
}
a3 := &Node{
Data: 3,
Fields: []*Node{a1, a2},
}
a1.Fields = append(a1.Fields, a3)
da3 := Dup(a3)
// print ast tree
_ = ast.Print(token.NewFileSet(),a3)
_ = ast.Print(token.NewFileSet(),da3)
}
输出如下:
// a3
0 *main.Node {
1 . Data: 3
2 . Fields: []*main.Node (len = 2) {
3 . . 0: *main.Node {
4 . . . Data: 1
5 . . . Fields: []*main.Node (len = 1) {
6 . . . . 0: *(obj @ 0) // 指向了0行的obj
7 . . . }
8 . . }
9 . . 1: *main.Node {
10 . . . Data: 2
11 . . }
12 . }
13 }
// da3
0 *main.Node {
1 . Data: 3
2 . Fields: []*main.Node (len = 2) {
3 . . 0: *main.Node {
4 . . . Data: 1
5 . . . Fields: []*main.Node (len = 1) {
6 . . . . 0: *(obj @ 0) // 同样指向了0行的obj
7 . . . }
8 . . }
9 . . 1: *main.Node {
10 . . . Data: 2
11 . . . Fields: []*main.Node (len = 0) {}
12 . . }
13 . }
14 }
再来调试看看运行时的地址情况:
a3的信息如下:
da3的信息如下:
可以看到,da3里面的地址与a3均不一样,但是值信息是一样的。
Read other posts