虽然go语言使用起来方便简单,但他有很多特性是比较与众不同的,在不了解的情况下,编码时候就会产生很多莫名其妙的bug。
channel
这里的channel默认是无缓冲的,但是有三个线程往里面写,而函数返回的时候只从中读取了一个,根据channel的特性,另外两个线程(go routine 个人别称 线程)中,另外两个线程会一直阻塞在ch <- true 这一行,造成资源泄漏(内存涨)。
解决办法
有两个解决办法,第一种使用select加上default的办法,这样,当channel无法写入的时候,就会触发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 建立起来,则可以避免这样的问题。
或者先用一个临时变量存储v的值,再用临时变量开启routine
range
原本以为在 循环刚开始的时候,把arr[1]的值改成10后,第二次循环的时候v会输出 10,结果arr[1]的值确实是改了,而 v 依旧输出是20。
原因是如果是数组等非指针类型,会在循环前复制一份,循环的时候使用的是复制的值。(channel/map/slice/指针数组等不会这样)
解决办法
尽量使用指针数组或者切片(slice)。
slice
同样是去掉第二个元素,用函数的方式却跟预料的不一样。
原因:实际上,切片作为参数的时候,虽然内容是指针,切片本身是拷贝,就是说函数内外 &arr 的地址不一样,但 &arr[n] 里面的元素的地址是一样的, 所以函数外的arr长度并没有减少。
解决办法
使用返回值重新赋值的方式。