1.简短声明的变量只能在函数内部使用。
:=为简短声明
var为声明
2.使用简短声明来重复声明变量。
不能用简短声明方式来单独为一个变量重复声明, := 左侧至少有一个新变量,才允许多变量的重复声明。
one := 1
one, two := 2, 3
3.不能使用简短声明来设置结构体字段的值。
struct 的变量字段不能使用 := 来赋值,所以使用预定义的变量来避免解决。
4.不小心覆盖了变量。
可能会让人误会 := 是一个赋值操作符。如果你在新的代码块中误用了 :=,编译不会报错,但是变量不会按你的预期工作:变量只在其作用域内生效。
这是 Go 开发者常犯的错,而且不易被发现。
可使用 vet 工具来诊断这种变量覆盖,Go 默认不做覆盖检查,添加 -shadow 选项来启用:
go tool vet -shadow main.go
注意 vet 不会报告全部被覆盖的变量,可以使用 go-nyet 来做进一步的检测:
$GOPATH/bin/go-nyet main.go
5.显式类型的变量无法使用 nil 来初始化。
nil 是 interface、function、pointer、map、slice 和 channel 类型变量的默认初始值,注意这里没有string哦,它的默认初始值为空字符串。但声明时需要指定值为nil的数据类型,否则编译器无法推断出变量的具体类型。
6.直接使用值为 nil 的 slice、map。
允许对值为 nil 的 slice 添加元素,但对值为 nil 的 map 添加元素则会造成运行时 panic。
7.string 类型的变量值不能为 nil。
8.数组array类型的值作为函数参数(注意不是slice)
在 C/C++ 中,数组(名)是指针。将数组作为参数传进函数时,相当于传递了数组内存地址的引用,在函数内部会改变该数组的值。
在 Go 中,数组是值。作为参数传进函数时,传递的是数组的原始值拷贝,此时在函数内部是无法更新该数组的。
slice和数组在形式上的区别:数组[3]int{1,2,3},slice是[]int{1,2,3}。
9.range 遍历 slice 和 array。
Go 中的 range 在遍历时会生成 2 个值,第一个是元素索引,第二个是元素的值。
10.slice 和 array 其实是一维数据。
可以使用原始的一维数组、“独立“ 的切片、“共享底层数组”的切片来创建动态的多维数组。
独立的切片
使用“共享底层数组”的切片。
11.访问 map 中不存在的 key。
Go 会返回元素对应数据类型的零值,比如 nil、’’ 、false 和 0,取值操作总有值返回,故不能仅仅通过取出来的值是否为‘’或者nil来判断 key 是不是在 map 中。
12.string 类型的值是常量,不可更改。
string 类型的值本质上是只读的二进制 byte slice,如果真要修改字符串中的字符,将 string 转为 []byte 修改后,再转为 string 即可:
xBytes := []byte(strText)
xBytes[0] = 'T'
上边的示例并不是更新字符串的正确姿势,因为一个 UTF8 编码的字符可能会占多个字节,比如汉字就需要 3~4 个字节来存储,此时更新其中的一个字节是错误的。
更新字串的正确姿势:将 string 转为 rune slice(此时 1 个 rune 可能占多个 byte),直接更新 rune 中的字符
xBytes := []rune(strText1)
xBytes[0] = '我'
13.string 的长度
lenChar := utf8.RuneCountInString(char)
14.log.Fatal 和 log.Panic 不只是 log
log 标准库提供了不同的日志记录等级,与其他语言的日志库不同,Go 的 log 包在调用 Fatal*()、Panic*() 时能做更多日志外的事,如中断程序的执行等.
15. range 迭代 map
与map的底层相关
如果你希望以特定的顺序(如按 key 排序)来迭代 map,要注意每次迭代都可能产生不一样的结果。
Go 的运行时是有意打乱迭代顺序的,所以你得到的迭代结果可能不一致。但也并不总会打乱,得到连续相同的 5 个迭代结果也是可能的。
16. 按位取反
很多编程语言使用 ~ 作为一元按位取反(NOT)操作符,Go 重用 ^ XOR 操作符来按位取反,同时 ^ 也是按位异或(XOR)操作符。
Go 也有特殊的操作符 AND NOT &^ 操作符,不同位才取1。
17. (*)程序退出时还有 goroutine 在执行
程序默认不等所有 goroutine 都执行完才退出,这点需要特别注意。
如果你的 goroutine 要做消息的循环处理等耗时操作,可以向它们发送一条 kill 消息来关闭它们,比如直接关闭一个它们都等待接收数据的 channel。
一定要主要函数传参的时候传指针。
18. 向无缓冲的 channel 发送数据,只要 receiver 准备好了就会立刻返回
只有在数据被 receiver 处理时,sender 才会阻塞。因运行环境而异,在 sender 发送完数据后,receiver 的 goroutine 可能没有足够的时间处理下一个数据。
19. 向已关闭的 channel 发送数据会造成 panic
从已关闭的 channel 接收数据是安全的。
接收状态值 ok 是 false 时表明 channel 中已没有数据可以接收了。
类似的,从有缓冲的 channel 中接收数据,缓存的数据获取完再没有数据可取时,状态值也是 false。
向已关闭的 channel 中发送数据会造成 panic。
可使用一个废弃 channel done 来告诉剩余的 goroutine 无需再向 ch 发送数据。此时 <- done 的结果是 {}
20.使用了值为 nil 的 channel
在一个值为 nil 的 channel 上发送和接收数据将永久阻塞: