Go語言深度拷貝工具deepcopy的使用教程
今天給大家推薦的工具是deepcopy,一個可以對指針、接口、切片、結構體、Map都能進行深拷貝的工具。在Go中需要對一個變量進行拷貝時分淺拷貝和深拷貝。淺拷貝就是拷貝后就是無論改變新值還是原值都對對另一個產生影響,比如切片。而深拷貝則是將目標值完全拷貝一份,消除這種影響。
實現(xiàn)原理分析
深拷貝的實現(xiàn)原理本質上是通過反射實現(xiàn)。通過將源對象轉換成接口,再對接口通過反射判斷其類型,進而進行深度拷貝。如下就是該包的完全實現(xiàn):
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內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang中空的切片轉化成 JSON 后變?yōu)?nbsp;null 問題的解決方案
在 Golang 中,經常需要將其他類型(例如 slice、map、struct 等類型)的數(shù)據(jù)轉化為 JSON 格式,有時候轉化的結果并不是預期中的,例如將一個空的切片轉化為 JSON 時,會變成"null",所以本文將給大家介紹一下解決方法,需要的朋友可以參考下2023-09-09
golang?sync.Cond同步機制運用及實現(xiàn)
在?Go?里有專門為同步通信而生的?channel,所以較少看到?sync.Cond?的使用,不過它也是并發(fā)控制手段里的一種,今天我們就來認識下它的相關實現(xiàn),加深對同步機制的運用2023-09-09
Golang對MongoDB數(shù)據(jù)庫的操作簡單封裝教程
mongodb官方沒有關于go的mongodb的驅動,因此只能使用第三方驅動,mgo就是使用最多的一種。下面這篇文章主要給大家介紹了關于利用Golang對MongoDB數(shù)據(jù)庫的操作簡單封裝的相關資料,需要的朋友可以參考下2018-07-07

