go新手容易犯的几个错误

版权声明:本文为博主原创文章,未经博主允许不得转载。 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到新切片中!!

猜你喜欢

转载自blog.csdn.net/qq_35440678/article/details/83722636