1.在Go语言中,函数参数都是以复制的方式(不支持以引用的方式)传递。 (比较特殊的是,Go语言闭包函数对外部变量是以引用的方式使用的)
闭包的例子
func main() {
for i := 0;i<3;i++ {
defer func() { println(i) } ()
}
}
//Output:
//3
//3
//3
可以这样解决
func main() {
for i := 0;i<3;i++ {
//通过函数传入i defer语句会马上对调用参数求值
defer func(i int) { println(i) } (i)
}
}
2.长度为0的数组(空数组)在内存中并不占用空间,比如可以用于管道的同步操作,但一般更倾向于无类型的匿名结构体代替空数组
c2 := make(chan struct{})
go func() {
fmt.Println("c2")
c2 <- struct{}{}
}()
<-c2
3.错误编码不会向后扩散是UTF-8编码的优秀特性之一
4.切片操作并不会复制底层的数据。底层的数据会被保存在内存中,直到它不再被引用,但是有时候因为一个小的内存引用而导致底层整个数组处于被使用的状态, 这会延迟垃圾回收器对底层数组的回收。
比如:
func FindPhoneNumber(fileName string) []byte() {
b,_ := ioutil.ReadFile(filename)
return regexp.MustCompile("[0-9]+").Find(b)
}
这段代码返回的[]byte指向保存整个文件的数组。
要解决这个问题,可以将感兴趣的数据复制到一个新的切片中(数据的传值是Go语言编程的一个哲学,虽然传值有一定代价,但是换取的好处是切断了对原始数据的依赖)
func FindPhoneNumber(fileName string) []byte() {
b,_ := ioutil.ReadFile(filename)
b = regexp.MustCompile("[0-9]+").Find(b)
return append([]byte{},b...)
}
5.在函数里面传指针,进而修改了切片的数据,传递到函数里的指针,跟数据原本的指针是同一个指针吗?(不相同,指针本身依然是传值的,但是指针指向的还是同一份数据而已)
6.在Go语言中,同一个Goroutine线程内部,顺序一致性的内存模型是得到保证的,但是不同Goroutine之间,并不满足顺序一致性的内存模型,需要通过明确定义的同步事件来作为同步的参数,如果两个事件不可排序,那么就说这两件事情是并发的
7.Go语言的并发编程哲学:不要通过共享内存来通信,而应通过通信来共享内存
8.要同时处理多个通道的发送或者接受操作,需要使用select关键字,select有多个分支时,会随机选择一个可用的通道分支,如果没有可用的通道分支,则选择default分支,否则会一直保持在阻塞状态
9.捕获异常不是最终目的,如果异常不可预测,直接输出异常信息是最好的处理方式