一、内存分配函数对比
1. new(Type)
ptr := new(int) // 返回 *int 指针 *ptr = 10
特点:
分配零值内存,返回指针
适用于所有类型(包括基本类型和复合类型)
对复合类型不初始化底层结构(如
new([]int)
会创建*[]int
指向 nil 切片)
2. make(Type, len, cap)
s := make([]int, 3, 5) // 长度3,容量5的切片 m := make(map[string]int) // 需省略cap参数 ch := make(chan int, 5) // 缓冲通道容量5
特点:
仅用于
slice
/map
/channel
的初始化分配内存并初始化底层数据结构(如切片的指针数组、哈希表桶等)
map
初始化时cap
参数会被忽略(建议省略)
二、容量与长度函数
1. cap()
适用类型
类型 | 含义 | 示例 |
---|---|---|
array | 等于数组长度(编译时确定) | cap([3]int{}) → 3 |
slice | 底层数组最大可扩展长度 | cap(make([]int,2,5)) → 5 |
channel | 缓冲区容量(非元素数量) | cap(make(chan int,5)) →5 |
2. len()
适用类型
类型 | 含义 | 示例 |
---|---|---|
array | 元素数量(编译时确定) | len([3]int{}) → 3 |
slice | 当前存储元素数量 | len(make([]int,2,5)) → 2 |
channel | 缓冲区中待读取元素数量 | ch <- 1; len(ch) →1 |
string | 字节数(非字符数) | len("中文") →6 |
map | 键值对数量 | len(map[int]bool{1:true}) →1 |
三、核心类型特性
1. 数组 (Array)
var arr [3]int // 长度和容量固定为3
编译期确定:长度是类型的一部分(
[3]int
≠[5]int
)值传递:赋值或传参时进行全量拷贝
2. 切片 (Slice)
s := make([]int, 2, 5) // len=2, cap=5 s = append(s, 3) // len=3, cap=5(无需扩容)
动态扩展:当
append
超容量时,按 2 倍策略扩容(直到 1024 后按 1.25 倍)底层共享:切片操作(如
s[1:3]
)共享同一数组,修改影响原数据反射修改(高风险操作):
sHeader := (*reflect.SliceHeader)(unsafe.Pointer(&s)) sHeader.Len = 4 // 强制修改长度(可能导致越界)
3. 字符串 (String)
str := "中文" byteLen := len(str) // 字节数 → 6 charCount := len([]rune(str)) // 字符数 → 2
不可变性:字符串内容无法直接修改,需转
[]byte
或[]rune
4. 通道 (Channel)
ch := make(chan int) // 无缓冲通道(cap=0) bufferedCh := make(chan int, 5) // cap=5
无缓冲通道:发送和接收操作同步阻塞
有缓冲通道:
len(ch)
表示当前缓冲元素数量cap(ch)
表示缓冲区最大容量
四、易错点与技巧
切片初始化对比:
var s1 []int // nil 切片(len=0, cap=0) s2 := make([]int, 0) // 空切片(底层数组指针非nil)
通道容量规范:
make(chan int, 5) // ✅ 正确:容量参数单独指定 make(chan int) // ✅ 正确:默认容量0(无缓冲)
字符串遍历:
str := "Hello, 世界" for i, r := range str { // i → 字节索引,r → Unicode 字符 }
通