下面从 运行时(runtime)实现层面 系统分析 Go 语言中 slice、map、channel、interface 的底层数据结构(基于 Go 1.x 标准实现)。
1. slice(切片)
底层结构
type slice struct {
array unsafe.Pointer // 指向底层数组
len int // 当前元素个数
cap int // 底层数组容量
}
关键点
-
非数组本身,只是一个描述符
-
多个 slice 可共享同一个底层数组
-
扩容规则:
-
cap < 1024:翻倍 -
cap ≥ 1024:按 ~25% 增长
-
-
作为参数传递时,复制的是 slice 结构体,而非底层数组
2. map(哈希表)
底层结构
type hmap struct {
count int // 元素个数
B uint8 // bucket 数量为 2^B
buckets unsafe.Pointer
oldbuckets unsafe.Pointer // 扩容时使用
extra *mapextra
}
bucket 结构
type bmap struct {
tophash [8]uint8
keys [8]keyType
values [8]valueType
overflow *bmap
}
核心机制
-
拉链法 + 溢出桶
-
负载因子 ≈ 6.5
-
渐进式扩容(incremental resizing)
-
key 必须可比较(
==、!=)
3. channel(通道)
底层结构
type hchan struct {
qcount uint // 队列中元素数
dataqsiz uint // 环形缓冲区大小
buf unsafe.Pointer // 环形缓冲区
elemsize uint16
closed uint32
elemtype *_type
sendx uint // 发送位置
recvx uint // 接收位置
recvq waitq // 接收等待队列
sendq waitq // 发送等待队列
lock mutex
}
等待队列
type waitq struct {
first *sudog
last *sudog
}
特性
-
支持 同步 / 异步 channel
-
发送/接收阻塞时,goroutine 进入等待队列
-
close(chan)会唤醒所有等待者
4. interface(接口)
4.1 空接口 interface{}
type eface struct {
_type *_type // 类型信息
data unsafe.Pointer // 数据指针
}
4.2 非空接口(带方法)
type iface struct {
tab *itab
data unsafe.Pointer
}
itab 结构
type itab struct {
inter *interfacetype // 接口类型
_type *_type // 具体类型
hash uint32
fun [1]uintptr // 方法地址数组
}
关键区别
| 类型 | 组成 |
|---|---|
| eface | 类型 + 数据 |
| iface | 接口表 + 数据 |
-
接口赋值发生 动态类型检查
-
方法调用通过 虚表(vtable)
5. 总结对比
| 类型 | 本质 | 是否并发安全 |
|---|---|---|
| slice | 结构体 + 数组引用 | ❌ |
| map | 哈希表 | ❌ |
| channel | 带锁的队列 | ✅ |
| interface | 类型包装器 | 取决于底层数据 |