Go语言make使用指南:slice、map、channel的初始化与动态特性
Contents
在 Go 语言中,切片 (slice)、map 和 channel 都是引用类型,使用前必须初始化,否则直接使用会导致运行时错误(nil 引用)。本文系统讲解 make 的作用、使用场景、动态变化特性,并配合示例分析。
1. 切片 (Slice)
1.1 使用 make 初始化
// 创建长度为5,容量为5的切片
s := make([]int, 5)
fmt.Println(s) // [0 0 0 0 0]
// 创建长度为3,容量为10的切片
t := make([]int, 3, 10)
fmt.Println(t, len(t), cap(t)) // [0 0 0] 3 10- 长度 (len):切片当前已有的元素个数
- 容量 (cap):切片底层数组可以容纳的最大元素个数
make会分配底层数组并初始化元素为零值,可以直接使用。
1.2 不使用 make 的情况
- 可以使用 数组字面量或切片字面量:
s := []int{1, 2, 3} // 已经初始化好,长度3,容量3- 适合初始化时已知元素的情况。
1.3 动态长度和容量
- 长度可以通过
append动态增加 - 容量会在需要时自动扩容
s := make([]int, 3, 5)
s = append(s, 10, 20)
fmt.Println(len(s), cap(s)) // 5 5
s = append(s, 30)
fmt.Println(len(s), cap(s)) // 6 10 自动扩容- 当长度超过容量时,Go 会自动分配更大的底层数组(通常容量翻倍),并把原元素复制过去。
1.4 截取切片(slice)
s := []int{1,2,3,4,5}
s2 := s[1:4] // [2 3 4]
fmt.Println(len(s2), cap(s2)) // 3 4- 长度 = end - start
- 容量 = 原切片容量 - start
- 截取不会复制元素,仍共享底层数组
2. map
2.1 使用 make 初始化
m := make(map[string]int) // 空 map
m["a"] = 1
m["b"] = 2
fmt.Println(m) // map[a:1 b:2]
// 可以指定容量(预估元素数目)
n := make(map[string]int, 10)make分配内存并返回可写 map- 适合 空 map,后续动态添加元素 的场景
2.2 不使用 make 的情况
- map 字面量初始化:
m := map[string]int{"a":1, "b":2, "c":3}- 已经分配好内存,可以直接使用
- 简洁,适合初始化时已知 key/value 的情况
2.3 动态长度与容量
- map 长度可以动态变化,随着元素添加/删除变化:
m := make(map[string]int)
m["a"] = 1
m["b"] = 2
fmt.Println(len(m)) // 2
delete(m, "a")
fmt.Println(len(m)) // 1map 容量不是显式可见
- Go 会根据元素数量动态调整底层存储
make(map[K]V, n)只是提供 初始预分配,性能优化用- map 的底层会自动扩容(类似哈希表重哈希)
3. channel
3.1 使用 make 初始化
// 无缓冲 channel
ch1 := make(chan int)
// 有缓冲 channel,容量5
ch2 := make(chan int, 5)- channel 必须用
make初始化 - 创建后可以直接
send和receive - 缓冲 channel 可以在不阻塞的情况下存储固定数量的元素
3.2 不使用 make 的情况
- channel 不能直接使用字面量初始化
var ch chan int
// ch <- 1 // ❌ panic: send on nil channel- 必须用
make或从函数返回已经初始化好的 channel
4. 总结对比表
| 类型 | 长度 | 容量 | 动态特性 | 初始化方式 |
|---|---|---|---|---|
| slice | 可变 | 可变(自动扩容) | append 可增长,切片截取可改变长度 | make([]T, len, cap) 或 []T{} |
| map | 可变 | 不可见,自动管理 | 添加/删除元素长度变化,容量自动扩张 | make(map[K]V) 或 map[K]V{} |
| channel | 可变 | 可见,容量固定 | 动态发送接收元素 | make(chan T, cap) |
5. 使用建议
slice:
- 预知长度/容量 →
make([]T, len, cap) - 已知元素 →
[]T{1,2,3}
- 预知长度/容量 →
map:
- 动态添加 →
make(map[K]V) - 已知 key/value →
map[K]V{"a":1,"b":2}
- 动态添加 →
channel:
- 必须用
make - 决定缓冲大小时直接传容量参数
- 必须用
6. 小结
make用于 分配并初始化 slice、map、channel- 字面量可用于 slice 和 map,初始化已知元素
new与make不同,返回指针且不初始化引用类型- nil 的 slice/map/channel 不能写入,只能读取零值
- 切片长度和容量可动态变化,map 长度可变,容量自动扩张