Go
标识符整体分类如下图所示:
Go
语言按类别有以下几种数据类型:
类型 | 描述 |
---|---|
布尔型 | 布尔型的值只可以是常量 true 或者 false |
数字类型 | 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码 |
字符串类型 | 字符串就是一串固定长度的字符连接起来的字符序列。 Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本 |
派生类型 | (a) 指针类型(Pointer) (b) 数组类型 © 结构化类型(struct) (d) Channel 类型 (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型 |
注意:
var a bool = true
a = 10 // cannot use 10 (type int) as type bool in assignment
a := 100
if a {
// Error: non-bool a (type int) used as if condition
println("true")
}
转换方式:
valueOfTypeB = typeB(valueOfTypeA)
a := 5.0
b := int(a)
package main
func main() {
var a int = 10
var b int32 = 10
b = a // cannot use a (type int) as type int32 in assignment
if a == b { // invalid operation: a == b (mismatched types int and int32)
println("a is equal b ")
}
}
类型 | 描述 |
---|---|
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) |
尽管在某些特定的运行环境下 int
、 uint
和 uintptr
的大小可能相等,但是它们依然是不同的类型,比如 int
和 int32
,虽然 int
类型的大小也可能是 32 bit,但是在需要把 int
类型当做 int32
类型使用的时候必须显示的对类型进行转换,反之亦然。
Go
语言中有符号整数采用 2 的补码形式表示,也就是最高 bit
位用来表示符号位,一个 n-bit 的有符号数的取值范围是从 -2 到 2-1。
无符号整数的所有 bit
位都用于表示非负数,取值范围是 0 到 2。例如,int8 类型整数的取值范围是从 -128 到 127,而 uint8
类型整数的取值范围是从 0 到 255。
哪些情况下使用 int
和 uint
?
程序逻辑对整型范围没有特殊需求。例如,对象的长度使用内建 len()
函数返回,这个长度可以根据不同平台的字节长度进行变化。实际使用中,切片或 map
的元素数量等都可以用 int
来表示。
事实上,内置的 len
函数返回一个有符号的 int
,我们可以像下面例子那样处理逆序循环。
medals := []string{"gold", "silver", "bronze"}
for i := len(medals) - 1; i >= 0; i-- {
fmt.Println(medals[i]) // "bronze", "silver", "gold"
}
如果 len
函数返回一个无符号数,那么 i
也将是无符号的 uint
类型,然后条件i >= 0
则永远为真。在三次迭代之后,也就是i == 0
时, i--
语句将不会产生 -1,而是变成一个 uint
类型的最大值(可能是2^64-1),然后 medals[i]
表达式运行时将发生 panic
异常,也就是试图访问一个 slice
范围以外的元素。
反之,在二进制传输、读写文件的结构描述、位运算、哈希和加密操作等时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,通常使用 uint
。
Unicode
字符 rune
类型是和 int32
等价的类型,通常用于表示一个 Unicode
码点。这两个名称可以互换使用。同样 byte
也是 uint8
类型的等价类型, byte
类型一般用于强调数值是一个原始的数据而不是一个小的整数。
一个算术运算的结果,不管是有符号或者是无符号的,如果需要更多的 bit
位才能正确表示的话,就说明计算结果是溢出了。超出的高位的 bit
位部分将被丢弃。如果原始的数值是有符号类型,而且最左边的 bit
位是1的话,那么最终结果可能是负的,例如 int8
的例子:
var u uint8 = 255
fmt.Println(u, u+1, u*u) // "255 0 1"
var i int8 = 127
fmt.Println(i, i+1, i*i) // "127 -128 1"
类型 | 描述 |
---|---|
float32 | IEEE-754 32位浮点型数 |
float64 | IEEE-754 64位浮点型数 |
complex64 | 32 位实数和虚数 |
complex128 | 64 位实数和虚数 |
一个 float32
类型的浮点数可以提供大约 6 个十进制数的精度,而 float64
则可以提供约 15 个十进制数的精度;通常应该优先使用 float64
类型,因为 float32
类型的累计计算误差很容易扩散,并且 float32
能精确表示的正整数并不是很大(译注:因为 float32
的有效 bit 位只有23个,其它的 bit 位用于指数和符号;当整数大于 23 bit 能表达的范围时, float32
的表示将出现误差):
var f float32 = 16777216 // 1 << 24
fmt.Println(f == f+1) // "true"!
用 Printf
函数的 %g
参数打印浮点数,将采用更紧凑的表示形式打印,并提供足够的精度,但是对应表格的数据,使用 %e
(带指数)或 %f
来控制保留几位小数的形式打印可能更合适。所有的这三个打印形式都可以指定打印的宽度和控制打印精度。
for x := 0; x < 8; x++ {
fmt.Printf("x = %d e^x = %8.3f\n", x, math.Exp(float64(x)))
}
上面代码打印 e
的幂,打印精度是小数点后三个小数精度和 8 个字符宽度:
x = 0 e^x = 1.000
x = 1 e^x = 2.718
x = 2 e^x = 7.389
x = 3 e^x = 20.086
x = 4 e^x = 54.598
x = 5 e^x = 148.413
x = 6 e^x = 403.429
x = 7 e^x = 1096.633
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
复数也可以用 ==
和 !=
进行相等比较。只有两个复数的实部和虚部都相等的时候它们才是相等的(译注:浮点数的相等比较是危险的,需要特别小心处理精度问题)。
参考:Go 语言圣经
类型 | 描述 |
---|---|
byte | 类似 uint8 |
rune | 类似 int32 |
uint | 32 或 64 位 |
int | 与 uint 一样大小 |
uintptr | 无符号整型,用于存放一个指针 |