Go语言的那些坑

来源:互联网 发布:mac电脑如何删除文件 编辑:程序博客网 时间:2024/06/08 09:06

Golang是我最喜欢的一门语言,它简洁、高效、易学习、开发效率高、还可以编译成机器码…
虽然它一出世,就饱受关注,而且现在在市面上逐渐流行开来,但是,它毕竟是一门新兴语言,还有很多让人不太习惯的地方(即坑,(^__^)),我作为新手,一边学习,一边踩坑,也希望对其他人有借鉴作用。

一、文件名字不要轻易以__test.go为结尾

Golang的source文件的命名和其他语言本无差别,但是Golang自带Unit test,它的unit test有个小规范:所有unit test文件都要以__test.go为结尾!
所以,当你命名一个非unit test文件为XXX_test.go,而且执意要编译时,就会报错:no buildable Go source files in XXXXXX(你的文件路径)
所以,切记,以__test.go为结尾的都是unit test的文件,且切记不要把unit test文件和普通Go文件放到一起,一定要把unit test文件集体放到一个目录中,否则会编译不过的。

二、语句fmt.Println("这里是汉字:" + 字符串变量)字符串变量的值打印不出来的问题



三、多个defer出现的时候,多个defer之间按照LIFO(后进先出)的顺序执行


四、panic中可以传任何值,不仅仅可以传string


五、用for range来遍历数组或者map的时候,被遍历的指针是不变的,每次遍历仅执行struct值的拷贝


六、Go中没有继承!没有继承!Go中是叫组合!是组合!


七、不管运行顺序如何,当参数为函数的时候,要先计算参数的值


八、注意是struct的函数,还是* struct的函数


九、make(chan int) 和 make(chan int, 1)是不一样的

chan一旦被写入数据后,当前goruntine就会被阻塞,知道有人接收才可以(即 “ <- ch”),如果没人接收,它就会一直阻塞着。而如果chan带一个缓冲,就会把数据放到缓冲区中,直到缓冲区满了,才会阻塞


十、golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。

select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是”IO操作”(不仅仅是取值<-channel,赋值channel<-也可以), select 会一直等待等到某个 case 语句完成,也就是等到成功从channel中读到数据。 则 select 语句结束


十一、golang中没有“对象”


十二、Go中的指针,*符号的含义

&的意思大家都明白的,取地址,假如你想获得一个变量的地址,只需在变量前加上&即可。


现在,我拿到a的地址了,但是我想取得a指针指向的值,该如何操作呢?用*号,*b即可。
*的意思是对指针取值。


*&可以相互抵消,同时注意,*&可以抵消,但是&*不可以;所以a*&a是一样的,和*&*&*&a也是一样的。

十三、os.Args获取命令行指令参数,应该从数组的1坐标开始


十四、数组切片slice的容量问题带来的bug

这特么是什么鬼?

这就要从Golang切片的扩容说起了;切片的扩容,就是当切片添加元素时,切片容量不够了,就会扩容,扩容的大小遵循下面的原则:(如果切片的容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。)如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组(这就是产生bug的原因);如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。
建议尽量避免bug的产生。

十五、map引用不存在的key,不报错


十六、map使用range遍历顺序问题,并不是录入的顺序,而是随机顺序


十七、channel作为函数参数传递,可以声明为只取(<- chan)或者只发送(chan <-)

一个函数在将channel作为一个类型的参数来声明的时候,可以将channl声明为只可以取值(<- chan)或者只可以发送值(chan <-),不特殊说明,则既可以取值,也可以发送值。


十八、使用channel时,注意goroutine之间的执行流程问题


一个基于无缓存channel的发送或者取值操作,会导致当前goroutine阻塞,一直等待到另外的一个goroutine做相反的取值或者发送操作以后,才会正常跑。
以上例子中的流程是这样的:

主goroutine等待接收,另外的那一个goroutine发送了“test”并等待处理;完成通信后,打印出”test”;两个goroutine各自继续跑自己的。
主goroutine等待接收,另外的那一个goroutine发送了“hello world”并等待处理;完成通信后,打印出”hello world”;两个goroutine各自继续跑自己的。
主goroutine等待接收,另外的那一个goroutine发送了“123”并等待处理;完成通信后,打印出”123”;两个goroutine各自继续跑自己的。
主goroutine等待接收,另外的那一个goroutine发送了“456”并等待处理;完成通信后,打印出”456”;两个goroutine各自继续跑自己的。
主goroutine等待接收,另外的那一个goroutine发送了“789”并等待处理;完成通信后,打印出”789”;两个goroutine各自继续跑自己的。

记住:Golang的channel是用来goroutine之间通信的,且通信过程中会阻塞。

原创粉丝点击