版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35440678/article/details/83722636
前言
最近写go遇到几个坑,做个记录,以免再犯。
高居榜首:通道未初始化
看下面的代码执行的结果是什么?
package main
import (
"fmt"
"time"
)
type test struct {
name string
}
type Object struct {
Ch chan *test
}
func main() {
go test1()
time.Sleep(100 * time.Second)
}
func test1() {
o := new(Object)
fmt.Println(&o, o.Ch)
for {
//执行下面这行,结果会是什么?
data,err := <-o.Ch
fmt.Println(data,err)
select {
case data := <-o.Ch:
fmt.Println(data)
case o.Ch <- &test{}:
fmt.Println("lll")
}
}
// o.Ch <- &test{}
fmt.Println(<-o.Ch)
}
当程序执行到data := <-o.Ch
会发生什么?
返回err?
panic?
还是其他?
正确答案是无限期永久阻塞!!!
原因是:
由于通道类型是引用类型,所以它的零值就是nil。换句话说,当我们只声明该类型的变量但没有用make函数对它进行初始化时,该变量的值就会是nil,对于值为nil的通道,不论它的具体类型是什么,对它的发送操作和接收操作都会永久地处于阻塞状态。它们所属的 goroutine 中的任何代码,都不再会被执行。
因此,建议:
通道一定要进行初始化,并且在定义最可能近的地方初始化。
切片copy问题
看下面代码:
// 深度遍历
func (a *Object) dfs(key string, path []string, adj map[string]*collection.Set) {
ok, err := utils.Contains(key, path)
if nil == err && ok {
return
}
path = append(path, key)
if len(newPath) > 1 {
a.Paths = append(a.availablePaths, newPath)
}
if set, ok := adj[key]; ok {
s := set.List()
for _, key2 := range s {
a.dfs(key2, newPath, adj)
}
}
}
func (a *Object) calAvailablePath(adj map[string]*collection.Set) {
for key := range adj {
a.dfs(key, []string{}, adj)
}
}
上面代码实现的是深度遍历的代码,但最后输出的结果是有重复结果的。
为什么?
原因出在path = append(path, key)
这一行。应该修改为:
//path = append(path, key)
newPath := make([]string, len(path)+1)
copy(newPath, append(path, key))
原因是每次将path append 时,是保持的引用,后续再append会修改原来的切片。
因此,需要重新make一个切片,将元素copy到新切片中!!