Contents

Go语言make使用指南:slice、map、channel的初始化与动态特性

在 Go 语言中,切片 (slice)mapchannel 都是引用类型,使用前必须初始化,否则直接使用会导致运行时错误(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)) // 1
  • map 容量不是显式可见

    • 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 初始化
  • 创建后可以直接 sendreceive
  • 缓冲 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. 使用建议

  1. slice

    • 预知长度/容量 → make([]T, len, cap)
    • 已知元素 → []T{1,2,3}
  2. map

    • 动态添加 → make(map[K]V)
    • 已知 key/value → map[K]V{"a":1,"b":2}
  3. channel

    • 必须用 make
    • 决定缓冲大小时直接传容量参数

6. 小结

  • make 用于 分配并初始化 slice、map、channel
  • 字面量可用于 slice 和 map,初始化已知元素
  • newmake 不同,返回指针且不初始化引用类型
  • nil 的 slice/map/channel 不能写入,只能读取零值
  • 切片长度和容量可动态变化,map 长度可变,容量自动扩张