今天给大家推荐的工具是deepcopy,一个可以对指针、接口、切片、结构体、Map都能进行深拷贝的工具。在Go中需要对一个变量进行拷贝时分浅拷贝和深拷贝。浅拷贝就是拷贝后就是无论改变新值还是原值都对对另一个产生影响,比如切片。而深拷贝则是将目标值完全拷贝一份,消除这种影响。
实现原理分析
深拷贝的实现原理本质上是通过反射实现。通过将源对象转换成接口,再对接口通过反射判断其类型,进而进行深度拷贝。如下就是该包的完全实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
package deepcopy import ( "reflect" "time" ) // Interface for delegating copy process to type type Interface interface { DeepCopy() interface {} } // Iface is an alias to Copy; this exists for backwards compatibility reasons. func Iface(iface interface {}) interface {} { return Copy (iface) } // Copy creates a deep copy of whatever is passed to it and returns the copy // in an interface{}. The returned value will need to be asserted to the // correct type. func Copy (src interface {}) interface {} { if src == nil { return nil } // Make the interface a reflect.Value original := reflect.ValueOf(src) // Make a copy of the same type as the original. cpy := reflect. New (original. Type ()).Elem() // Recursively copy the original. copyRecursive(original, cpy) // Return the copy as an interface. return cpy. Interface () } // copyRecursive does the actual copying of the interface. It currently has // limited support for what it can handle. Add as needed. func copyRecursive(original, cpy reflect.Value) { // check for implement deepcopy.Interface if original.CanInterface() { if copier, ok := original. Interface ().( Interface ); ok { cpy.Set(reflect.ValueOf(copier.DeepCopy())) return } } // handle according to original's Kind switch original.Kind() { case reflect.Ptr: // Get the actual value being pointed to. originalValue := original.Elem() // if it isn't valid, return. if !originalValue.IsValid() { return } cpy.Set(reflect. New (originalValue. Type ())) copyRecursive(originalValue, cpy.Elem()) case reflect. Interface : // If this is a nil, don't do anything if original.IsNil() { return } // Get the value for the interface, not the pointer. originalValue := original.Elem() // Get the value by calling Elem(). copyValue := reflect. New (originalValue. Type ()).Elem() copyRecursive(originalValue, copyValue) cpy.Set(copyValue) case reflect. Struct : t, ok := original. Interface ().(time.Time) if ok { cpy.Set(reflect.ValueOf(t)) return } // Go through each field of the struct and copy it. for i := 0 ; i < original.NumField(); i++ { // The Type's StructField for a given field is checked to see if StructField.PkgPath // is set to determine if the field is exported or not because CanSet() returns false // for settable fields. I'm not sure why. -mohae if original. Type ().Field(i).PkgPath != "" { continue } copyRecursive(original.Field(i), cpy.Field(i)) } case reflect.Slice: if original.IsNil() { return } // Make a new slice and copy each element. cpy.Set(reflect.MakeSlice(original. Type (), original. Len (), original. Cap ())) for i := 0 ; i < original. Len (); i++ { copyRecursive(original.Index(i), cpy.Index(i)) } case reflect. Map : if original.IsNil() { return } cpy.Set(reflect.MakeMap(original. Type ())) for _, key := range original.MapKeys() { originalValue := original.MapIndex(key) copyValue := reflect. New (originalValue. Type ()).Elem() copyRecursive(originalValue, copyValue) copyKey := Copy (key. Interface ()) cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue) } default : cpy.Set(original) } } |
基本使用
拷贝切片
1
2
3
4
5
|
a := [] int { 1 , 2 , 3 } dst := deepcopy. Copy (a) a1 := dst.([] int ) a1[ 0 ] = 2 fmt. Println (a, a1) //a:[1 2 3] a1:[2 2 3] |
拷贝map
1
2
3
4
5
6
7
8
|
a := make ( map [ string ] int ) a[ "k1" ] = 1 a[ "k2" ] = 2 a[ "k3" ] = 3 dst := deepcopy. Copy (a) a1 := dst.( map [ string ] int ) a1[ "k1" ] = 10 fmt. Println (a, a1) //a:map[k1:1 k2:2 k3:3] a1:map[k1:10 k2:2 k3:3] |
更多项目详情请查看如下链接。
开源项目地址:https://github.com/mohae/deepcopy
到此这篇关于Go语言深度拷贝工具deepcopy的使用教程的文章就介绍到这了,更多相关Go深度拷贝deepcopy内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/7143030425839992863