Golang深拷贝浅拷贝
在了解原型设计模式之前我们需要新知道Golang的深拷贝与浅拷贝之间的区别。
推荐大家新看看Slice 和 Map那么常见的坑:https://blog.csdn.net/weixin_/article/details/
github:https://github.com/zhumengyifang/GolangDesignPatterns
数据结构:
//速度速值 type Speed int //风扇转速 type FanSpeed struct { Speed Speed } //售价 type Money struct { Length float64 } //内存数量以及大小 type Memory struct { Count int MemorySize []int } //电脑信息 type Computer struct { SystemName string //系统名字 UseNumber int //使用次数 Memory Memory //存储 Fan map[string]FanSpeed //风扇 Money Money //售价 }
浅拷贝:
接触过 Java或者C#的同学应该知道浅拷贝对于值类型的话是完全拷贝一份,而对于引用类型是拷贝其地址。也就是拷贝的对象修改引用类型的变量同样会影响到源对象。
这里Golang同理,在上述测试类型中涉及到 Slice 和 Map的修改则会互相影响。
测试1:
func ComputerStart1() { Pc1 := Computer{ SystemName: "Windows", UseNumber: 1000, Memory: Memory{Count: 4, MemorySize: []int{32, 32, 32, 32}}, Fan: map[string]FanSpeed{"left": {2500}, "right": {2000}}, Money: Money{123.45}, } //浅拷贝 Pc2:=Pc1 fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) //修改切片内容以及map信息影响Pc1 Pc2.SystemName ="MacOs" Pc2.UseNumber =100 Pc2.Memory.Count =2 Pc2.Memory.MemorySize[0]=8 Pc2.Memory.MemorySize[1]=8 Pc2.Memory.MemorySize[2]=0 Pc2.Memory.MemorySize[3]=0 Pc2.Fan["left"]=FanSpeed{2000} Pc2.Fan["right"]=FanSpeed{1500} fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) }
输入信息:
PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{Windows 1000 {4 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}}, Pc2:{MacOs 100 {2 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}}
对于PC2的修改影响到了PC1的Slice 和 Map
测试2:
func ComputerStart2() { Pc1 := Computer{ SystemName: "Windows", UseNumber: 1000, Memory: Memory{Count: 4, MemorySize: []int{32, 32, 32, 32}}, Fan: map[string]FanSpeed{"left": {2500}, "right": {2000}}, Money: Money{123.45}, } //浅拷贝 Pc2:=Pc1 fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) ModifyCat(Pc2) fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) } func ModifyCat(pc Computer) { fmt.Printf("PcInfo Pc1:%v\n", pc) pc.SystemName ="MacOs" pc.UseNumber =100 pc.Memory.Count =2 pc.Memory.MemorySize[0]=8 pc.Memory.MemorySize[1]=8 pc.Memory.MemorySize[2]=0 pc.Memory.MemorySize[3]=0 pc.Fan["left"]=FanSpeed{2000} pc.Fan["right"]=FanSpeed{1500} fmt.Printf("PcInfo Pc1:%v\n", pc) }
输入:
PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{MacOs 100 {2 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}} PcInfo Pc1:{Windows 1000 {4 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}}, Pc2:{Windows 1000 {4 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}}
这里在方法中修改PC2同样影响到了 PC1以及PC2,是因为在Golang中方法中传递的参数同样被拷贝了一份,他们修改的Slice 和 Map都是同一份地址。
那么对于浅拷贝来说如何避免这种情况的发生呢?
测试3:
func ComputerStart2() { Pc1 := Computer{ SystemName: "Windows", UseNumber: 1000, Memory: Memory{Count: 4, MemorySize: []int{32, 32, 32, 32}}, Fan: map[string]FanSpeed{"left": {2500}, "right": {2000}}, Money: Money{123.45}, } //浅拷贝 Pc2:=Pc1 fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) //切片以及map新空间互不影响 Pc2.SystemName ="MacOs" Pc2.UseNumber =100 Pc2.Memory =Memory{Count: 2, MemorySize: []int{8, 8}} Pc2.Fan =map[string]FanSpeed{"left": {2000}, "right": {1500}} Pc2.Money =Money{1000.45} fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) }
输出:
PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:{MacOs 100 {2 [8 8]} map[left:{2000} right:{1500}] {1000.45}}
既然只有Slice 和 Map会受到影响我们这里重新给定地址重新生成一个Slice和Map就可以不受影响。
深拷贝
对于深拷贝就比较好了解了,任何对象都会被完完整整的拷贝一份,拷贝对象与被拷贝对象不存在如何联系,也就不会互相影响。如果你需要拷贝的对象中没有引用类型,那么对于Golang而言使用浅拷贝就可以了。
基于序列化和反序列化来实现对象的深度拷贝:
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) }
需要深拷贝的变量必须首字母大写才可以被拷贝
测试1:
func ComputerStart4() { Pc1 := &Computer{ SystemName: "Windows", UseNumber: 1000, Memory: Memory{Count: 4, MemorySize: []int{32, 32, 32, 32}}, Fan: map[string]FanSpeed{"left": {2500}, "right": {2000}}, Money: Money{123.45}, } //深拷贝 Pc2:= new(Computer) if err:= deepCopy(Pc2,Pc1);err!=nil{ panic(err.Error()) } fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) ModifyCat1(*Pc2) fmt.Printf("PcInfo Pc1:%v, Pc2:%v\n", Pc1, Pc2) }
输出:
PcInfo Pc1:&{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:&{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}} PcInfo Pc1:{MacOs 100 {2 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}} PcInfo Pc1:&{Windows 1000 {4 [32 32 32 32]} map[left:{2500} right:{2000}] {123.45}}, Pc2:&{Windows 1000 {4 [8 8 0 0]} map[left:{2000} right:{1500}] {123.45}}
可以看到PC2经过浅拷贝(参数传递)在修改Slice和Map受到影响的也只有PC2和PC2的浅拷贝对象。对于PC1没有任何影响。
下一章原型设计模式:https://blog.csdn.net/weixin_/article/details/
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/211631.html原文链接:https://javaforall.net
