标识符
- 字母或下划线开头
- 之后只能出现数字、字母、下划线
- 大小写敏感
| break | default | func | interface | select |
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const | fallthrough | if | range | type |
| continue | for | import | return | var |
此外,还有大约30多个预定义的名字,比如
int和true等,主要对应内建的常量、类型和函数
- 内建常量:
true false iota nil- 内建类型:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error- 内建函数:
make len cap new append copy close delete
complex real imag
panic recover
这些内部预先定义的名字并不是关键字,你可以再定义中重新使用它们。在一些特殊的场景中重新定义它们也是有意义的,但是也要注意避免过度而引起语义混乱。
标识符一般使用驼峰命名法:
- 变量名:
xxxYyyZzz- 常量名:
XXX_YYY_ZZZ- 函数名:
XxxYyyZzz- 方法名:
XxxYyyZzz- 包名:一般是小写字母组成
【注】有些有特殊含义的缩写单词要字母全大写,如
ID,HTTP等
基本类型
整型
| 类型 | 符号 | 长度范围 |
|---|---|---|
| uint8 | 无符号 | 8位整型 (0 到 255) |
| uint16 | 无符号 | 16位整型 (0 到 65535) |
| uint32 | 无符号 | 32位整型 (0 到 4294967295) |
| uint64 | 无符号 | 64位整型 (0 到 18446744073709551615) |
| int8 | 有符号 | 8位整型 (-128 到 127) |
| int16 | 有符号 | 16位整型 (-32768 到 32767) |
| int32 | 有符号 | 32位整型 (-2147483648 到 2147483647) |
| int64 | 有符号 | 64位整型 (-9223372036854775808 到 9223372036854775807) |
Unicode字符rune类型是和int32等价的类型(别名),通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型(别名),byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
有符号整数采用补码表示
Go 也有基于架构的类型,例如:int、uint 和 uintptr,这些类型的长度都是根据运行程序所在的操作系统类型所决定的。
不管它们的具体大小,
int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是不同的类型,即使int的大小也是32 bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然。
浮点型
主要是为了表示小数,也可细分为float32和float64两种。浮点数能够表示的范围可以从很小到很巨大,这个极限值范围可以在math包中获取,math.MaxFloat32表示float32的最大值,大约是3.4e38,math.MaxFloat64大约是1.8e308,两个类型最小的非负值大约是1.4e-45和4.9e-324。
float32大约可以提供6位有效数字的精度,作为对比,float64可以提供16位有效数字的精度。通常情况应该优先选择float64,因为float32的精确度较低,在累积计算时误差扩散很快,而且float32能精确表达的最小正整数并不大,浮点数和整数的底层解释方式完全不同。
不要对浮点型进行
==判断,因为本身就是近似存储
小数点前面或后面的零都可以被省略(例如.707或1.)。很小或很大的数最好用科学计数法书写,通过e或E来指定指数部分:
const Avogadro = 6.02214129e23 // 阿伏伽德罗常数
const Planck = 6.62606957E-34 // 普朗克常数
如果一个函数返回的浮点数结果可能失败,最好的做法是用单独的标志报告失败,像这样:
func compute() (value float64, ok bool) {
// ...
if failed {
return 0, false
}
return result, true
}
复数
Go语言提供了两种精度的复数类型:complex64和complex128,分别对应float32和float64两种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实部和虚部:
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y) // (-5+10i)
fmt.Println(real(x*y)) // -5
fmt.Println(imag(x*y)) // 10
如果一个浮点数面值或一个十进制整数面值后面跟着一个i,例如3.141592i或2i,它将构成一个复数的虚部,复数的实部是0:
fmt.Println(1i * 1i) // (-1+0i), i^2 = -1
在常量算术规则下,一个复数常量可以加到另一个普通数值常量(整数或浮点数、实部或虚部),我们可以用自然的方式书写复数,就像1+2i或与之等价的写法2i+1。上面x和y的声明语句还可以简化:
x := 1 + 2i
y := 3 + 4i
复数也可以用==和!=进行相等比较。只有两个复数的实部和虚部都相等的时候它们才是相等的。
浮点数的相等比较是危险的,需要特别小心处理精度问题。想想Java的BigInteger!
布尔型
一个布尔类型的值只有两种:true和false。if和for语句的条件部分都是布尔类型的值,并且==和<等比较操作也会产生布尔型的值。一元操作符!对应逻辑非操作,因此!true的值为false。
布尔值并不会隐式转换为数字值0或1,反之亦然。必须使用一个显式的if语句辅助转换:
i := 0
if b {
i = 1
}
如果需要经常做类似的转换, 包装成一个函数会更方便:
// btoi returns 1 if b is true and 0 if false.
func btoi(b bool) int {
if b {
return 1
}
return 0
}
数字到布尔型的逆转换则非常简单, 不过为了保持对称, 我们也可以包装一个函数:
// itob reports whether i is non-zero.
func itob(i int) bool { return i != 0 }
字符串
字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其它包括 XML 和 JSON 在内,也都使用该编码。由于该编码对占用字节长度的不定性,Go 中的字符串里面的字符也可能根据需要占用 1 至 4 个字节,这与其它语言如 C++、Java 或者 Python 不同(Java 始终使用 2 个字节)。Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。
字符串是一种值类型,且值不可变,即创建某个文本后你无法再次修改这个文本的内容;更深入地讲,字符串是字节的定长数组。
Go 支持以下 2 种形式的字面值:
-
解释字符串:
该类字符串使用双引号括起来,其中的相关的转义字符将被替换,这些转义字符包括:
:换行符:回车符:tab 键u或U:Unicode 字符\:反斜杠自身
-
非解释字符串:
该类字符串使用反引号括起来,支持换行,并且禁止转义,例如:
`This is a raw string ` 中的 ` \` 会被原样输出。
和 C/C++不一样,Go 中的字符串是根据长度限定,而非特殊字符