布尔类型
用于存储逻辑值,只有 true 和 false 两个取值。布尔值通常作为布尔表达式的求值结果,可与其他布尔表达式进行组合与运算:
-
&&:逻辑与(AND),两个操作数都为真时结果为真 -
||:逻辑或(OR),至少有一个操作数为真时结果为真 -
!:逻辑非(NOT),对布尔值取反
数值类型
Go 的基本数值类型中,最常用的是整型与浮点型。
整型
Go 的整型分为平台无关整型与平台相关整型两类,主要区别在于其位宽是否随 CPU 架构变化。
平台无关整型在任何 CPU 架构或操作系统中的长度都固定,Go 提供如下类型:
| 类别 | 类型 | 长度 | 取值范围 |
|---|---|---|---|
| 有符号整型 | int8 |
1 字节 | [-128, 127] |
int16 |
2 字节 | [-32768, 32767] | |
int32 |
4 字节 | [-2147483648, 2147483647] | |
int64 |
8 字节 | [-9223372036854775808, 9223372036854775807] | |
| 无符号整型 | uint8 |
1 字节 | [0, 255] |
uint16 |
2 字节 | [0, 65535] | |
uint32 |
4 字节 | [0, 4294967295] | |
uint64 |
8 字节 | [0, 18446744073709551615] |
有符号与无符号的本质差别在于二进制最高位是否被解释为符号位,从而导致取值范围不同。

平台相关整型的位宽会根据运行平台变化,Go 原生提供 3 种平台相关整型:
| 类型 | 32 位平台 | 64 位平台 |
|---|---|---|
int |
32 位(4 字节) | 64 位(8 字节) |
uint |
32 位(4 字节) | 64 位(8 字节) |
uintptr |
足以存储任意指针值的无符号整数 | 足以存储任意指针值的无符号整数 |
需要特别注意:由于这些类型的长度与平台相关,在编写有可移植性要求的代码时,不应假设其固定长度。如果需要确认目标平台上的大小,可以使用 unsafe.Sizeof:
package main
import (
"fmt"
"unsafe"
)
func main() {
var a, b = int(5), uint(6)
var p uintptr = 0x12345678
fmt.Println("有符号整型a的长度为:", unsafe.Sizeof(a))
fmt.Println("无符号整型b的长度为:", unsafe.Sizeof(b))
fmt.Println("指针类型p的长度为:", unsafe.Sizeof(p))
}
整型溢出问题
当运算结果超出该类型的取值范围时,会发生整型溢出。对无符号整型与有符号整型而言,溢出通常体现为按模回绕(wrap around),结果仍落在取值范围内,但可能与预期不符:
var s int8 = 127
s += 1 // 预期128,实际结果变为-128
var u uint8 = 1
u -= 2 // 预期-1,实际结果变为255
字面值与格式化输出
Go 的整数(整型)字面值支持多种进制形式。早期 Go 支持:
a := 53 // 十进制
b := 0700 // 八进制(旧写法),以“0”为前缀
c1 := 0xaabbcc // 十六进制,以“0x”为前缀
c2 := 0Xddeeff // 十六进制,以“0X”为前缀
自 Go 1.13 起,支持二进制字面值与更清晰的八进制前缀 0o:
d1 := 0b10000001 // 二进制,以“0b”为前缀
d2 := 0B10000001 // 二进制,以“0B”为前缀
e1 := 0o700 // 八进制,以“0o”为前缀
e2 := 0O700 // 八进制,以“0O”为前缀
此外,还支持数字分隔符 _,可用于分组或分隔前缀与数字主体:
a := 5_3_7 // 十进制:537
b := 0b_1000_0111 // 二进制:0b10000111
c1 := 0_700 // 八进制(旧写法):0700
c2 := 0o_700 // 八进制:0o700
d1 := 0x_5c_6d // 十六进制:0x5c6d
可以用标准库 fmt 对整型进行不同进制的格式化输出:
var a int8 = 59
fmt.Printf("%b\n", a) // 二进制:111011
fmt.Printf("%d\n", a) // 十进制:59
fmt.Printf("%o\n", a) // 八进制:73
fmt.Printf("%O\n", a) // 八进制(带0o前缀):0o73
fmt.Printf("%x\n", a) // 十六进制(小写):3b
fmt.Printf("%X\n", a) // 十六进制(大写):3B
浮点类型
浮点类型的使用场景更集中,常见于科学计算、图形图像处理与仿真、多媒体与游戏、人工智能等领域。
二进制表示
Go 中浮点类型的二进制表示遵循 IEEE 754 标准。
IEEE 754 定义了多种浮点格式:单精度(32 位)、双精度(64 位)以及若干扩展格式。Go 提供
float32 与float64,分别对应 IEEE 754 的单精度与双精度格式。
双精度在指数与尾数上使用更多比特位,精度更高,日常开发中更常用;同时,未显式指定类型的浮点常量默认是 float64。
字面值格式与输出
浮点字面值主要包括十进制小数形式与科学计数法形式。
十进制表示:
3.1415
.15 // 整数部分为0可省略
81.80
82. // 小数部分为0可省略
科学计数法(十进制):
6674.28e-2 // 6674.28 * 10^(-2) = 66.7428
.12345E+5 // 0.12345 * 10^5 = 12345
科学计数法(十六进制):
0x2.p10 // 2.0 * 2^10 = 2048
0x1.Fp+0 // 1.9375 * 2^0 = 1.9375
十六进制浮点字面值中,小数部分使用十六进制表示,但指数部分是十进制,且底数为 2(使用
p/P表示)。
使用 fmt 可对浮点数进行格式化输出:
var f float64 = 123.45678
fmt.Printf("%f\n", f) // 123.456780
fmt.Printf("%e\n", f) // 1.234568e+02
fmt.Printf("%x\n", f) // 0x1.edd3be22e5de1p+06
其中 %e 输出十进制科学计数法,%x 输出十六进制科学计数法(浮点)。
复数类型
在数学中,形如 z = a + bi(a、b 均为实数,a 为实部,b 为虚部)的数称为复数。
Go 提供两种复数类型:complex64 与 complex128。complex64 的实部与虚部均为 float32,complex128 的实部与虚部均为 float64。若未显式指定类型,复数常量默认类型为 complex128。
复数的初始化方式包括:
使用复数字面值:
var c = 5 + 6i
var d = 0o123 + .12345E+5i // 83+12345i
使用内建函数 complex 创建复数:
var c = complex(5, 6) // 5+6i
var d = complex(0o123, .12345E+5) // 83+12345i
使用内建函数 real 和 imag 获取实部与虚部:
var c = complex(5, 6)
r := real(c) // 5
i := imag(c) // 6
字符串类型
Go 原生支持 string,主要带来以下特性:
-
string不可变,提升并发场景下的安全性与可预测性。 - 字符串不以
'\0' 结尾,长度是显式记录的,len(s)为常数时间复杂度 O(1)。 - 支持原始字符串字面值(raw string literal),可用反引号
`包裹,多行内容与反斜杠等均不进行转义;唯一不能直接包含的字符是反引号本身。 - 源码对非 ASCII 字符提供原生支持(源文件通常以 UTF-8 编码存储),降低跨环境乱码风险。
Go 字符串的组成
-
字节视角:字符串是一个(可为空的)字节序列,
len返回字节数。单个字节只是数据,并不一定对应一个“字符”。var s = "中国人" fmt.Printf("the length of s = %d\n", len(s)) // 9 for i := 0; i < len(s); i++ { fmt.Printf("0x%x ", s[i]) // 0xe4 0xb8 0xad 0xe5 0x9b 0xbd 0xe4 0xba 0xba } fmt.Printf("\n") -
字符(rune)视角:字符串可视为 Unicode 码点序列(按 UTF-8 解码得到的 rune 序列)。
var s = "中国人" fmt.Println("the character count in s is", utf8.RuneCountInString(s)) // 3 for _, c := range s { fmt.Printf("0x%x ", c) // 0x4e2d 0x56fd 0x4eba } fmt.Printf("\n")Go 使用 Unicode 码点(code point)来表示字符;上例输出的是每个字符对应的码点值。
rune 类型与字符字面值
Go 使用 rune 表示一个 Unicode 码点。rune 是 int32 的别名,与 int32 等价。
字符字面量通常使用单引号括起:
'a' // ASCII字符
'中' // Unicode字符
'\n' // 换行
'\'' // 单引号字符
也可使用 Unicode 转义序列表示字符:
'\u4e2d' // 中
'\U00004e2d' // 中
'\u0027' // 单引号
其中 \u 后跟 4 个十六进制数,\U 后跟 8 个十六进制数。此外,还可用十六进制或八进制转义表示单字节值(常用于表示 ASCII):
'\x27' // 十六进制的单引号
'\047' // 八进制的单引号
字符串字面值
解释型字符串字面值使用双引号:
"abc\n" // 包含换行
"中国人" // 直接包含中文
"\u4e2d\u56fd\u4eba" // Unicode转义表示“中国人”
"\U00004e2d\U000056fd\U00004eba"
"中\u56fd\u4eba" // 混合写法
"\xe4\xb8\xad\xe5\x9b\xbd\xe4\xba\xba" // UTF-8字节序列
十六进制形式的 \x.. 表示的是字节序列,并不直接等同于 Unicode 码点;上例字节序列恰好是字符串“中国人”的 UTF-8 编码。
Go 字符串类型的内部表示
通过查看 Go 源码可以看到字符串的运行时表示(不同包中的结构体名称不同,但语义一致):
// $GOROOT/src/reflect/value.go
// StringHeader代表字符串的运行时表示形式
type StringHeader struct {
Data uintptr
Len int
}
// $GOROOT/src/runtime/string.go
type stringStruct struct {
str unsafe.Pointer
len int
}
字符串值本质上是一个“描述符”:包含指向底层字节序列的指针与长度字段;字符串数据存放在指针所指向的底层内存中。因此将 string 作为函数参数传递通常开销很小(仅复制指针与长度)。

字符串类型的常见操作
下标操作
字符串支持下标访问,但得到的是某个位置上的字节而非字符:
var s = "中国人"
fmt.Printf("0x%x\n", s[0]) // 0xe4,为“中”的UTF-8编码第一个字节
字符迭代
Go 常见的两种迭代方式:
-
使用常规
for,按字节遍历:var s = "中国人" for i := 0; i < len(s); i++ { fmt.Printf("index: %d, value: 0x%x\n", i, s[i]) }输出:
index: 0, value: 0xe4 index: 1, value: 0xb8 index: 2, value: 0xad index: 3, value: 0xe5 index: 4, value: 0x9b index: 5, value: 0xbd index: 6, value: 0xe4 index: 7, value: 0xba index: 8, value: 0xba -
使用
for range,按 UTF-8 解码后的 rune(码点)遍历,i是字节偏移:var s = "中国人" for i, v := range s { fmt.Printf("index: %d, value: 0x%x\n", i, v) }输出:
index: 0, value: 0x4e2d index: 3, value: 0x56fd index: 6, value: 0x4eba
如需统计字符数量,推荐使用
utf8.RuneCountInString(注意函数名为 RuneCountInString)。
字符串连接
虽然字符串不可变,但可以基于旧字符串生成新字符串。Go 支持用 + 与 += 进行连接:
s := "Rob Pike, "
s = s + "Robert Griesemer, "
s += "Ken Thompson"
fmt.Println(s) // Rob Pike, Robert Griesemer, Ken Thompson
大量拼接时,+ 可能带来额外分配与拷贝开销,常见替代方案包括 strings.Builder、strings.Join、fmt.Sprintf 等。
字符串比较
Go 字符串支持 ==、!=、>=、<=、>、< 等比较运算符。比较采用字典序(按字节序列逐字节比较;对 UTF-8 字符串通常表现为按编码序比较)。
func main() {
// ==
s1 := "世界和平"
s2 := "世界" + "和平"
fmt.Println(s1 == s2) // true
// !=
s1 = "Go"
s2 = "C"
fmt.Println(s1 != s2) // true
// < and <=
s1 = "12345"
s2 = "23456"
fmt.Println(s1 < s2) // true
fmt.Println(s1 <= s2) // true
// > and >=
s1 = "12345"
s2 = "123"
fmt.Println(s1 > s2) // true
fmt.Println(s1 >= s2) // true
}
字符串相等性判断会先比较长度;长度相同再比较内容(实现层面可能会进行指针与长度等快速路径优化,但语义上等价于内容比较)。
字符串转换
Go 支持 string 与 []byte、[]rune 的双向转换,通过显式类型转换即可完成:
var s string = "中国人"
// string -> []rune
rs := []rune(s)
fmt.Printf("%x\n", rs) // [4e2d 56fd 4eba]
// string -> []byte
bs := []byte(s)
fmt.Printf("%x\n", bs) // e4b8ade59bbde4baba
// []rune -> string
s1 := string(rs)
fmt.Println(s1) // 中国人
// []byte -> string
s2 := string(bs)
fmt.Println(s2) // 中国人