Golang深拷贝浅拷贝

Golang深拷贝浅拷贝Golang 深拷贝浅拷贝在了解原型设计模式之前我们需要新知道 Golang 的深拷贝与浅拷贝之间的区别 推荐大家新看看 Slice 和 Map 那么常见的坑 https blog csdn net weixin article details github https github com zhumengyifan GolangDesign

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

(0)
上一篇 2026年3月18日 下午9:59
下一篇 2026年3月18日 下午9:59


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号