Go克隆几种方式
序列化的方式实现深度拷贝
最简单的方式是基于序列化和反序列化来实现对象的深度复制:
func deepCopy(dst, src interface{}) error {
    var buf bytes.Buffer
    if err := gob.NewEncoder(&buf).Encode(src); err != nil {
        return err
    }
    return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
}测试用例
import (
 "bytes"
 "encoding/gob"
 "encoding/json"
 "fmt"
 "log"
 "reflect"
 "testing"
 "github.com/mohae/deepcopy"
)
type Basics struct {
 A string
 B int
 C []string
}
func TestClone1(t *testing.T) {
 var src2 = &Basics{
  A: "hello world",
  B: 34,
  C: []string{"1213", "1312"},
 }
 dst := new(Basics)
 if err := deepCopy(dst, src2); err != nil {
  log.Fatal(err)
 }
 log.Printf("%+v", dst)
}执行结果:
=== RUN   TestClone1
2021/12/23 10:37:56 &{A:hello world B:34 C:[1213 1312]}
--- PASS: TestClone1 (0.00s)
PASS反射实现深度拷贝
深度复制可以基于reflect包的反射机制完成, 但是全部重头手写的话会很繁琐.
/深度克隆,可以克隆任意数据类型
func DeepClone(src interface{}) (interface{}, error) {
 typ := reflect.TypeOf(src)
 if typ.Kind() == reflect.Ptr {
  typ = typ.Elem()
  dst := reflect.New(typ).Elem()
  b, _ := json.Marshal(src)
  if err := json.Unmarshal(b, dst.Addr().Interface()); err != nil {
   return nil, err
  }
  return dst.Addr().Interface(), nil
 } else {
  dst := reflect.New(typ).Elem()
  b, _ := json.Marshal(src)
  if err := json.Unmarshal(b, dst.Addr().Interface()); err != nil {
   return nil, err
  }
  return dst.Interface(), nil
 }
}测试用例
import (
 "bytes"
 "encoding/gob"
 "encoding/json"
 "fmt"
 "log"
 "reflect"
 "testing"
 "github.com/mohae/deepcopy"
)
type Basics struct {
 A string
 B int
 C []string
}
func TestDeepClone(t *testing.T) {
 var src = &Basics{
  A: "hello world",
  B: 34,
  C: []string{"1213", "1312"},
 }
 dst, _ := DeepClone(src)
 fmt.Println(dst)
}执行结果:
=== RUN   TestDeepClone
&{hello world 34 [1213 1312]}
--- PASS: TestDeepClone (0.00s)
PASS借助包深拷贝
"github.com/mohae/deepcopy"
使用方式如下:
dst := deepcopy.Copy(src)测试用例
import "github.com/mohae/deepcopy"
type BasicsSmall struct {
 a string
 b int
 c []string
}
func TestDeepCopy(t *testing.T) {
 //src := &User{Name: "xiaomng", Age: 100}
 var src = &BasicsSmall{
  a: "hello world",
  b: 34,
  c: []string{"1213", "1312"},
 }
 dst := deepcopy.Copy(src)
 fmt.Println(dst)
}测试结果:
=== RUN   TestDeepCopy
&{ 0 []}
--- PASS: TestDeepCopy (0.00s)
PASS为啥会出现上面的结果,因为 struct 结构,首字母都是小写的!!!
换个用例
import "github.com/mohae/deepcopy"
type User struct {
 Name string // 小写变量,不能被deepCopy函数拷贝成功
 Age  int
}
func TestDeepCopy(t *testing.T) {
 src := &User{Name: "xiaomng", Age: 100}
 //var src = &BasicsSmall{
 // a: "hello world",
 // b: 34,
 // c: []string{"1213", "1312"},
 //}
 dst := deepcopy.Copy(src)
 fmt.Println(dst)
}执行结果:
=== RUN   TestDeepCopy
&{xiaomng 100}
--- PASS: TestDeepCopy (0.00s)
PASS总结
上述拷贝有个问题,结构体中有小写成员变量时,上述方式无效。
欢迎关注公众号:程序员财富自由之路

公众号:程序员财富自由之路
关注我们,了解更多
再给个代码例子吧:
package utils
import (
    "encoding/json"
    "reflect"
)
//浅克隆,可以克隆任意数据类型,对指针类型子元素无法克隆
//获取类型:如果类型是指针类型,需要使用Elem()获取对象实际类型
//获取实际值:如果值是指针类型,需要使用Elem()获取实际数据
//说白了,Elem()就是获取反射数据的实际类型和实际值
func Clone(src interface{}) interface{} {
    typ := reflect.TypeOf(src)
    if typ.Kind() == reflect.Ptr { //如果是指针类型
        typ = typ.Elem()               //获取源实际类型(否则为指针类型)
        dst := reflect.New(typ).Elem() //创建对象
        data := reflect.ValueOf(src)   //源数据值
        data = data.Elem()             //源数据实际值(否则为指针)
        dst.Set(data)                  //设置数据
        dst = dst.Addr()               //创建对象的地址(否则返回值)
        return dst.Interface()         //返回地址
    } else {
        dst := reflect.New(typ).Elem() //创建对象
        data := reflect.ValueOf(src)   //源数据值
        dst.Set(data)                  //设置数据
        return dst.Interface()         //返回
    }
}
//深度克隆,可以克隆任意数据类型
func DeepClone(src interface{}) interface{} {
    typ := reflect.TypeOf(src)
    if typ.Kind() == reflect.Ptr { //如果是指针类型
        typ = typ.Elem()                          //获取源实际类型(否则为指针类型)
        dst := reflect.New(typ).Elem()            //创建对象
        b, _ := json.Marshal(src)                 //导出json
        json.Unmarshal(b, dst.Addr().Interface()) //json序列化
        return dst.Addr().Interface()             //返回指针
    } else {
        dst := reflect.New(typ).Elem()            //创建对象
        b, _ := json.Marshal(src)                 //导出json
        json.Unmarshal(b, dst.Addr().Interface()) //json序列化
        return dst.Interface()                    //返回值
    }
}参考资料
- https://houbb.github.io/2019/01/09/java-deep-copy
 - https://www.codenong.com/cs105839518/
 










