網站首頁 編程語言 正文
今天給大家推薦的工具是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
原文鏈接:https://juejin.cn/post/7143030425839992863
相關推薦
- 2023-06-19 深入了解Golang中Slice切片的使用_Golang
- 2021-12-18 C/C++?Qt?數據庫與TreeView組件綁定詳解_C 語言
- 2023-09-12 利用ImportBeanDefinitionRegistrar手動向Spring容器注入Bean
- 2022-10-06 C++?pimpl機制詳細講解_C 語言
- 2022-12-23 Android入門之彈出式對話框的實現_Android
- 2022-02-28 ./node_modules/taro-ui/dist/weapp/index.ts Module
- 2022-09-18 Python?Pandas實現DataFrame合并的圖文教程_python
- 2023-10-12 react報錯:Can’t perform a React state update on an u
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支