这必然是一路风景
1、go的时间time.sleep()其中的参数默认单位不是秒而是微秒 go中有专门的时间值time.Second/Minute/Hour...
2、channel的 make(chan int, arg)第二个参数定义channel buffer,默认是unbuffer,单线程使用的时候必须要定义,否则会被阻塞(unbuffer意思是只要我收到了,我就会阻塞在这个地方,等人来取,单线程就会直接报错了编不过,例子如下)https://www.jianshu.com/p/f12e1766c19f
func Ping(ping chan<- int, s int) {
ping <- s
}
func Pong(ping <-chan int, pong chan<- int) {
msg := <-ping
pong <- msg
}
func ChannelDirect() {
pi := make(chan int) // 会报错当ping <- s的时候
po := make(chan int)
Ping(pi, 1)
Pong(pi, po)
fmt.Println(<-po)
}
3、fmt.printf("%T", arg) 判断arg的类型
4、channel synchronization 其实就是通过在goroutine里面放置channel的方式,保证goroutine中的代码运行完毕
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
done <- true
}
func main() {
done := make(chan bool, 1)
go worker(done)
<-done // 这里阻塞直到goroutine运行完
}
5、goroutines leaking 永远不要在不知道它将如何停止的情况下启动一个goroutine,因为是并发的,所以会一直占用内存,其中一种情况就是channel没有设置buffer,则默认为阻塞的,如果channel阻塞且正好在goroutines中,则会造成此goroutine永远释放不了
6、数组和切片的区别:1.定义的时候数组必须定长度或者[...]让机器判定长度,切片则不用。多维数组只有第一层能使用[...]
7、数组传递的是值,是值类型,map和slice传递的是指针
8、切片是对底层数组的进一层封装,所以切片是由数组切来的时候,并不是复制了一份,而是直接的引用,改变数组的值会同时更改切片的值,切片的赋值也有相同效果,赋值的结果是复制了引用,底层数组是同一个
9、当切片append元素时,如果append后长度未超出cap长度,则依然适用上面的规则,如果append后超出了,则会复制一个新的底层数组重新指向,此时再更改上面的数组就不再影响slice
func ArraySlice() {
new_array := [3]int{1, 3, 5}
new_slice := new_array[:2]
fmt.Println(new_slice)
new_slice = append(new_slice, 9, 10)
new_array[1] = 7
fmt.Println(new_slice)
fmt.Println(cap(new_slice))
}
stdout-->
[1 3]
[1 3 9 10]
6 // 原来是3
9、切片没有删除方法,可以append(slice[:index], slice[index+1:]...),删除掉index位置的元素就是从index+1开始append到index位置其实,注意第二个后面的三个点是go的语法糖,必须要加的,不然会直接append一个切片上去,其实就类似python的*args的*
10、切片是否为空必须要用len是否为0来判断,不能弄nil
11、new与make的区别:
12、map是没有cap的,所以make(map, 111)第二个参数是没用的(目前暂时认为,不确定),map也是一个指向底层数据的指针,是引用类型
13、go的goroutine并发不是越多越好,因为协程是go的内部处理调度,绑定的是固定几个cpu的内核线程,所以当goroutine到达一定数量,cpu被一直满载占用,此时再创建协程运算效率就并不会有什么明显提升了,而go中协程的调度负荷反而会越来越重,有可能还会造成性能的下降(个人理解)
14、for index, stu := range stus {},这个时候index和stu是固定的内存空间,range的作用把stus解析后赋值给前面两个变量,前面两个变量的地址是不变的,所以在这里面尽量不要有关于前面两个变量的指针操作
15、go语言指针的使用需要声明后用new分配内存空间,struct的属性占用连续的内存空间,排列方法是属性内存和结构体内存的对齐,可以从这个方面优化大体积结构体
16、go语言的方法接收者用指针比较常见,struct是值类型,如果接收者是值类型则修改只在局部函数中生效,方法可以对任意本地类型生效,例如type MyInt int,那么给MyInt加一个方法完全可以
什么时候应该使用指针类型接收者
需要修改接收者中的值
接收者是拷贝代价比较大的大对象
保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。
17、go的继承通过结构体的嵌套实现,被嵌套的结构体是父类,结构体变量大写开头为公开,小写为私有(一定要注意,json.Marshal就不会读取私有的,如果是tag 小写是可以的例如`json:"name"`)
原文:https://www.cnblogs.com/seasen/p/12981788.html