Go语言深度拷贝工具deepcopy的使用教程
更新时间:2022年09月15日 11:25:43 作者:Go学堂
今天给大家推荐的工具是deepcopy,一个可以对指针、接口、切片、结构体、Map都能进行深拷贝的工具,感兴趣的小伙伴快跟随小编一起学习学习
今天给大家推荐的工具是deepcopy,一个可以对指针、接口、切片、结构体、Map都能进行深拷贝的工具。在Go中需要对一个变量进行拷贝时分浅拷贝和深拷贝。浅拷贝就是拷贝后就是无论改变新值还是原值都对对另一个产生影响,比如切片。而深拷贝则是将目标值完全拷贝一份,消除这种影响。
实现原理分析
深拷贝的实现原理本质上是通过反射实现。通过将源对象转换成接口,再对接口通过反射判断其类型,进而进行深度拷贝。如下就是该包的完全实现:
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) } }
基本使用
拷贝切片
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
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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
相关文章
Golang中空的切片转化成 JSON 后变为 null 问题的解决方案
在 Golang 中,经常需要将其他类型(例如 slice、map、struct 等类型)的数据转化为 JSON 格式,有时候转化的结果并不是预期中的,例如将一个空的切片转化为 JSON 时,会变成"null",所以本文将给大家介绍一下解决方法,需要的朋友可以参考下2023-09-09
最新评论