标识符
- 字母或下划线开头
- 之后只能出现数字、字母、下划线
- 大小写敏感
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 种形式的字面值:
-
解释字符串:
该类字符串使用双引号括起来,其中的相关的转义字符将被替换,这些转义字符包括:
u
或U
:Unicode 字符\
:反斜杠自身
-
非解释字符串:
该类字符串使用反引号括起来,支持换行,并且禁止转义,例如:
`This is a raw string ` 中的 ` \` 会被原样输出。
和 C/C++不一样,Go 中的字符串是根据长度限定,而非特殊字符