Go知识库程序员Go语言

go语言的一些陷阱

2017-11-09  本文已影响206人  lazypos

        虽然go语言使用起来方便简单,但他有很多特性是比较与众不同的,在不了解的情况下,编码时候就会产生很多莫名其妙的bug。

channel

channel示例代码

        这里的channel默认是无缓冲的,但是有三个线程往里面写,而函数返回的时候只从中读取了一个,根据channel的特性,另外两个线程(go routine 个人别称 线程)中,另外两个线程会一直阻塞在ch <- true 这一行,造成资源泄漏(内存涨)。

解决办法

        有两个解决办法,第一种使用select加上default的办法,这样,当channel无法写入的时候,就会触发default退出。

换成select和default

        另一个办法是创建channel的时候,容量足够大,大于等于3,使得写入不阻塞。

创建管道指定容量大小

go routine

示例代码

        以为会输出1,2,3 实际却输出了3,3,3,原因是V这个变量是同一个地址重复使用,三次循环 &V 的地址都是一样的,只是V的值改变了,而GetId()函数的调用是用指针是调用的,所以船体给go routine的是V的地址,三次都一样。然而go routine是异步开启的,循环执行太快导致三个go routine得到的该地址值是最后一个了

解决办法

        如果在gov.GetId() 之后加上足够时间的sleep()让该 routine 建立起来,则可以避免这样的问题。

加上sleep确保线程开启

        或者先用一个临时变量存储v的值,再用临时变量开启routine

使用临时变量

range

示例代码

        原本以为在 循环刚开始的时候,把arr[1]的值改成10后,第二次循环的时候v会输出 10,结果arr[1]的值确实是改了,而 v 依旧输出是20。

        原因是如果是数组等非指针类型,会在循环前复制一份,循环的时候使用的是复制的值。(channel/map/slice/指针数组等不会这样)

解决办法

        尽量使用指针数组或者切片(slice)。

创建的时候是切片 循环的时候转成切片

slice

示例代码

        同样是去掉第二个元素,用函数的方式却跟预料的不一样。

        原因:实际上,切片作为参数的时候,虽然内容是指针,切片本身是拷贝,就是说函数内外 &arr 的地址不一样,但 &arr[n] 里面的元素的地址是一样的, 所以函数外的arr长度并没有减少。

解决办法

        使用返回值重新赋值的方式。

返回切片
上一篇下一篇

猜你喜欢

热点阅读