go语言学习遇到的问题
最近在努力学习go,这个编程语言语法和写法的都和其他的编程语言有着比较大的差异。所以特地记录一下学习go遇到的问题。
GOPATH和go module
这个问题比较神奇,也是我学习这个编程语言中遇到的比较拧巴的问题。网上的绝大多数的教程都会让你配置GOPATH,然后go程序都必须在GOPATH的SRC这个文件下运行,而这个GOPATH是你windows的环境变量。
在以前GOPATH下会对go程序的编写严格进行,必须在src下,并且在很多包,或者git下其他的程序之后,整个项目就会变得非常混乱。
这样听起来很奇怪不是吗?身为一个比较新鲜的编程语言,既然会有这么愚蠢的方法。
而网上的教程绝大多数度是让你去配置环境,最后用vscode去编写go程序,但是我自己在用IDEA去写的时候却不会遇到要配置GOPATH这个问题,这是为什么呢?然后我去网上进行了一番搜索之后,了解了一个新鲜的事物,叫做go module。
而go 1.13版本之后就支持了go module,这使得程序的编写不用在指定的文件夹进行,而是用模块化的方式去编写程序。
而现在,在有了MODULE之后,GOPATH现在常用于存放第三方API,不进行程序编写了。go module允许go在任意地方进行编写,非常人性化。
1 2 3 4 5 6 7
| 当你在GOPATH下使用go module时 用环境变量 GO111MODULE 开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是 auto。
GO111MODULE=off 无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包。 GO111MODULE=on 模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖。 GO111MODULE=auto 在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持。 但是我建议新开别的文件夹去写go程序,不要在GoPATH下
|
所以,我们应该使用 go mod init your_project_name
去实现go的模块化编写
浅拷贝和深拷贝的问题
在我用go写leetcode39的时候,遇到了一个奇怪的问题,我加入ans的值是【2,2,2,3】,可是运行结果后,值就变为【2,2,2,1】了,真是奇怪。我在func中有且仅有一个对ans的操作,这真的让我思考了很久,然后一个一个的debug。。。。。。。。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| 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 { 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
|
最后,我花了一个小时,终于找到了问题所在,问题在于这个:
1 2 3 4 5
| correctArr := currentArray correctArr = append(correctArr, candidates[i])
smallerArr := currentArray smallerArr = append(smallerArr, candidates[i])
|
它们之间是浅拷贝关系,我对smallerArr 进行append也会影响到已经加入了ans的数组!!!!!
- 调用append函数时,当原有长度加上新追加的长度如果超过容量则会新建一个数组,新旧切片会指向不同的数组;
- 如果没有超过容量则在原有数组上追加元素,新旧切片会指向相同的数组,这时对其中一个切片的修改会同时影响到另一个切片。
改动了正确代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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 { correctArr := make([]int, len(currentArray)) copy(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
|
未完待续。。。。。
1、深拷贝(Deep Copy):
拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时,可分别释放。
值类型的数据,默认全部都是深复制,Array、Int、String、Struct、Float,Bool。
2、浅拷贝(Shallow Copy):
拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。
引用类型的数据,默认全部都是浅复制,Slice,Map。