Go的拷贝问题 | 青训营笔记

76 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

今天尝试用go去写算法题,遇到了一些问题

浅拷贝和深拷贝的问题

在我用go写leetcode39的时候,遇到了一个奇怪的问题,我加入ans的值是【2,2,2,3】,可是运行结果后,值就变为【2,2,2,1】了,真是奇怪。我在func中有且仅有一个对ans的操作,这真的让我思考了很久,然后一个一个的debug。。。。。。。。

代码如下:

func combinationSum(candidates []int, target int) [][]int {
   ans = nil
   var currentArray []int
   //不断递归搜索的问题
   for i := 0; i < len(candidates); i++ {
      currentArray = nil
      currentArray = append(currentArray, candidates[i])
      //如果当前就是,那么久不用继续了
      if candidates[i] == target {
         singerAns := []int{candidates[i]}
         ans = append(ans, singerAns)
      } else {
         //否则递归性搜索
         combinationSumRecursiveFunction(candidates, currentArray, i, candidates[i], target)
      }
   }

   return ans
}
func combinationSumRecursiveFunction(candidates, currentArray []int, begin, sum, target int) {
   for i := begin; i < len(candidates); i++ {
      if candidates[i]+sum == target {
         //不要去改动currentArray
         //等于就加入ans
         correctArr := currentArray
         correctArr = append(correctArr, candidates[i])
         ans = append(ans, correctArr)
      } else if candidates[i]+sum < target {
         //小于则可以直接递归,再次搜索
         smallerArr := currentArray
         smallerArr = append(smallerArr, candidates[i])
         combinationSumRecursiveFunction(candidates, smallerArr, i, candidates[i]+sum, target)
      } else {
         //大于则没有继续搜索的必要了,什么都不做就可以了
      }
   }
​
}
​
var ans [][]int

最后,我花了一个小时,终于找到了问题所在,问题在于这个:

correctArr := currentArray
correctArr = append(correctArr, candidates[i])
//========================================================================================
smallerArr := currentArray
smallerArr = append(smallerArr, candidates[i])
​

它们之间是浅拷贝关系,我对smallerArr 进行append也会影响到已经加入了ans的数组!!!!!

  1. 调用append函数时,当原有长度加上新追加的长度如果超过容量则会新建一个数组,新旧切片会指向不同的数组;
  2. 如果没有超过容量则在原有数组上追加元素,新旧切片会指向相同的数组,这时对其中一个切片的修改会同时影响到另一个切片。

总结:

深拷贝

拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时,可分别释放。值类型的数据,默认全部都是深复制,Array、Int、String、Struct、Float,Bool。

浅拷贝

拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。引用类型的数据,默认全部都是浅复制,Slice,Map。

对于go语言的学习的看法

可以去类似于去菜鸟教程这个网站,去初步的了解编程语言的写法。

或者是类似于哔哔哔哩这样的视频网站,直接照这视频一步一步的去学习它的写法,不过这种方法比较消耗时间。但是我觉得如果你有一定的编程基础,学这个go真的很简单,没有什么复杂地方。你仅需要注意的是,语法有些不同,你可能要花一段时间去适应它的写法。