Menu

Golang 数据类型:int、float64、string、bool、byte、rune

Go 的内置类型:各种整数的大小和范围、float32 与 float64、bool、string、byte 与 rune、复数、零值,以及如何用 %T 打印值的类型。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

Go 的基本类型包括数字、布尔值和字符串。每个变量都恰好有一个在编译期确定的类型,Go 从不会替你在类型之间自动转换。%T 可以打印任何值的类型:

注意 'G' 打印出来是 71,类型是 int32:单引号括起来的字符是 rune,而 rune 是一个数字(Unicode 码点)。rune 是 int32 的别名(同一个类型的第二个名字),所以 %T 报告的是 int32。同样,byte 报告的是 uint8。

整数

类型大小范围
int88 位-128 至 127
int1616 位-32,768 至 32,767
int3232 位约 -21亿 至 21亿
int6464 位约 -9.2×10¹⁸ 至 9.2×10¹⁸
uint8(byte)8 位0 至 255
uint1616 位0 至 65,535
uint3232 位0 至约 43亿
uint6464 位0 至约 1.8×10¹⁹
int、uint32 或 64 位平台字长
uintptr与平台相关保存指针值,用于底层代码

默认使用 int。 len() 返回 int,切片索引是 int,循环计数器也是 int。在所有 64 位平台上,int 都是 64 位。当大小是约定的一部分时,再使用固定大小的类型:二进制文件格式中的 int32,原始字节用的 uint8,以纳秒为单位的 Unix 时间戳用的 int64。

对于“不可能为负”的数量(比如计数),不要使用无符号类型。减到零以下时,它会回绕成一个巨大的数字,而不是产生一个你能发现的负数。

上限与溢出

math 包为每个上限都提供了常量。在运行时,溢出的整数运算会悄无声息地回绕:

没有 panic,也没有错误:127 + 1 变成了 -128。只有常量表达式会在编译期检查(var b int8 = 128 无法通过编译)。如果你的数据可能溢出,请在运算之前检查,或者使用 math/big。

整数字面量

million := 1_000_000   // underscores for readability (Go 1.13+)
mask := 0xFF           // hexadecimal
perm := 0o755          // octal (also the older form 0755)
flags := 0b1010        // binary

浮点数

类型大小精度
float3232 位约 6 到 9 位有效数字
float6464 位约 15 到 17 位有效数字

带小数点或指数的字面量(2.5、1e6)默认是 float64,math 包接受和返回的也是 float64。除非大型数组的内存很重要,否则就用它。

浮点数是二进制的,所以大多数十进制小数都只是近似值:

由此得出两条规则:运算之后绝不要用 == 比较浮点数;也绝不要用浮点数存储金额,请用以“分”为单位的整数,或者使用十进制数库。

浮点数除以零得到 +Inf、-Inf 或 NaN,而不会 panic。整数除以零会在运行时 panic(runtime error: integer divide by zero),除数是常量零时则是编译错误。

布尔值

bool 保存 true 或 false,零值是 false。Go 不会把数字、空字符串或 nil 当作布尔值。if count {} 是编译错误,要写成 if count > 0 {}。运算符是 &&、|| 和 !,其中 && 和 || 会短路求值。

字符串

string 是一个不可变的字节序列,通常是 UTF-8 文本。len(s) 计算的是字节数,而不是字符数:

é 在 UTF-8 中占两个字节,所以五个字符的 len 是 6。双引号字符串会处理 \n 这样的转义序列;反引号括起来的原始字符串不会,并且可以跨越多行。strings 包在字符串页面中讲解,UTF-8 的细节在 rune 和字节页面中深入介绍。

byte 和 rune

别名等同于保存的内容
byteuint8一个字节的原始数据
runeint32一个 Unicode 码点

它们是别名,而不是新类型:byte 和 uint8 无需转换即可互换。名字只是说明这个数字代表什么。

复数

Go 内置了复数类型 complex64 和 complex128,配合 real、imag 以及 math/cmplx 包使用:

很少有程序需要它们,但信号处理和一些数值计算代码会用到。

复合类型与引用类型

基本类型可以组合成复合类型。每种类型都有自己的页面:

类型示例零值
数组[3]int三个零
切片[]intnil
mapmap[string]intnil
结构体struct{ X, Y int }每个字段都是零值
指针*intnil
函数func(int) intnil
通道chan intnil
接口error、anynil

any 是 interface{} 的别名(从 Go 1.18 开始),可以保存任何类型的值。

命名类型

你可以基于已有类型定义一个新类型。它的底层表示相同,但是一个不同的类型,并且可以拥有方法:

type Celsius float64
type UserID int64

var t Celsius = 21.5
var f float64 = t // compile error: cannot use t (variable of float64 type Celsius) as float64 value in variable declaration

这种严格正是目的所在:UserID 不会被意外传到需要 OrderID 的地方。确实需要时再显式转换:float64(t)。转换规则见类型转换页面,数字与字符串之间的转换见 strconv 包的函数。

零值

每种类型都有零值,也就是变量在你赋值之前保存的值:数字是 0,bool 是 false,字符串是 "",指针、切片、map、通道、函数和接口是 nil。Go 中不存在未初始化的变量。

常见问题

Go 中的 int 有多大?

在 64 位平台(amd64、arm64)上,int 和 uint 是 64 位;在 32 位平台上是 32 位。如果需要固定大小,比如用于文件格式或网络协议,请使用 int32、int64、uint8 等类型。普通的计数器、索引和长度用 int 即可。

Go 中如何打印变量的类型?

使用 %T 动词:fmt.Printf("%T\n", x) 会打印 int、float64、[]string、main.User 等。在代码中,reflect.TypeOf(x) 以一个可供检查的值的形式返回同样的信息。

Go 中 byte 和 rune 有什么区别?

byte 是 uint8 的别名,保存一个字节的原始数据。rune 是 int32 的别名,保存一个 Unicode 码点。字符串是字节序列;用 for range 遍历字符串时,会把它解码成一个个 rune。

Go 中应该用 float32 还是 float64?

除非有特别的理由,否则用 float64。它是浮点数字面量的默认类型,也是 math 包使用的类型,大约有 15 到 17 位有效数字,而 float32 只有大约 6 到 9 位。只有在需要让大型数组的内存减半,或者要匹配外部格式时,才选择 float32。

Go 中 int 的最大值是多少?

使用 math 包中的常量:math.MaxInt(在 64 位平台上是 9223372036854775807)、math.MinInt、math.MaxInt64、math.MaxUint32 等。运行时超出上限的运算会悄无声息地回绕,不会 panic。

Coddy 编程语言插图

和 Coddy 一起学编程

开始