append是唯一安全扩展切片的方式,直接赋值越界会panic;make的三个参数分别控制切片长度/容量、map哈希桶数、chan缓冲区大小;len/cap语义因类型而异,clear仅重置长度与元素零值而不释放底层数组。

append 会 realloc 底层数组,但不总是;make 初始化切片时没指定容量就等于长度;len 和 cap 对字符串返回字节数而非字符数;clear 不清空底层数组,只重置长度和元素零值——这些不是“细节”,是写错就 panic 或内存泄漏的点。
什么时候该用 append 而不是直接赋值?
切片是引用类型,直接 s[i] = x 只能改已有索引位置;要加新元素,必须用 append。它不是“语法糖”,而是唯一安全扩展切片长度的方式。
- 错误写法:
s := []int{1,2}; s[2] = 3→ panic: index out of range - 正确写法:
s = append(s, 3)→ 返回新切片,可能指向新底层数组 - 合并多个切片:
append(a, b...),注意...展开符不能省 - 预分配可大幅减少扩容:比如知道最终长度是 1000,就
make([]int, 0, 1000)再append
make 的三个参数分别控制什么?
make 只接受 []T、map[K]V、chan T 三种类型,且行为完全不同:
-
make([]int, 5)→ 长度 5,容量也 5(底层数组大小 = 5) -
make([]int, 5, 10)→ 长度 5,容量 10(底层数组大小 = 10,还能追加 5 个不 realloc) -
make(map[string]int, 100)→ 预分配哈希桶空间,避免后续插入时频繁 rehash(但不是“初始长度”) -
make(chan int, 5)→ 创建带缓冲的通道,容量为 5;make(chan int)容量为 0(同步通道)
len 和 cap 在字符串、切片、通道上含义不同
别想当然套用一个逻辑——它们的语义随类型而变:
- 字符串:
len(s)返回字节数(UTF-8 编码下中文占 3 字节),cap(s)不可用(编译报错) - 切片:
len(s)是当前元素个数,cap(s)是底层数组从s[0]开始还能容纳多少元素 - 通道:
len(ch)是当前已缓冲元素数,cap(ch)是缓冲区总大小(未缓冲通道为 0) - 常见坑:
cap对 map、string、array 不合法;len对函数、int 等也不合法
clear 看似简单,但重用切片时容易误判状态
clear(s) 后 len(s) == 0,但 cap(s) 不变,底层数组也没释放。这既是优势也是陷阱:
- 优势:后续
append可复用内存,避免分配 - 陷阱:
clear(s)后s仍是原底层数组的视图,若其他变量还持有该数组(比如通过s[1:]截取过),修改会影响它们 - 映射
clear(m)等价于for k := range m { delete(m, k) },但更快,且不会触发迭代器失效问题 - Go 1.21+ 才支持,旧版本需手动循环或重置:如
s = s[:0]
append 返回新切片却可能共享底层数组、make 的第二个参数在 map 里不叫“长度”、clear 不等于 nil——这些边界状态,一不留神就让程序在压测时突然卡住或返回脏数据。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











