make返回的是值类型([]int、map[string]int、chan int),非指针;因其本身是引用类型,header已含指针语义,可直接使用,无需且不应额外取地址。

不能直接用 make 得到指针,它返回的是值类型([]int、map[string]int、chan int),不是指针;想拿到指针必须显式取地址——但绝大多数时候你根本不需要这么做。
为什么 make 返回的不是指针?
make 的设计目标就是初始化引用类型本身:它分配底层数据结构(如底层数组、哈希表、环形缓冲区),并填充 header 字段(指针+长度+容量等),返回一个「可用的值」。这个值在函数间传递时,本身已含指针语义,修改其内容会影响原值——所以 Go 不鼓励、也不需要你再套一层 *[]int。
-
make([]int, 5)返回[]int,内部 header 已指向有效数组,可直接append -
make(map[string]int)返回map[string]int,非 nil,可直接赋值m["k"] = 1 - 若写
var p *[]int = new([]int),得到的是*[]int,但解引用后仍是nilslice,调用append(*p, 1)会 panic
什么时候真需要 &make(...)?
极少数场景下需把 slice/map/channel 当作整体传参并修改其 header(比如重置为另一个 make 出来的值),这时才用取地址:
- 函数参数是
*[]int,想在函数内替换整个 slice header(而非只改元素) - 实现类似「动态切换底层数组」的逻辑(例如内存池中换出旧 slice、换入新预分配的 slice)
- 测试或调试中需观察 header 变化,比如验证
cap是否被修改
示例:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
func resetSlice(p *[]int) {
*p = make([]int, 0, 1024) // 替换整个 slice header
}
s := []int{1, 2}
resetSlice(&s) // s 现在是 len=0, cap=1024 的新 slice
常见错误:误以为 new([]int) + make 能简化流程
有人写 p := new([]int); *p = make([]int, 5),这完全多余:
-
new([]int)只分配一个零值 slice header(三个字段全 0),不分配底层数组 - 紧接着
*p = make(...)是一次额外赋值,且*p是可寻址的,不如直接s := make([]int, 5) - 这种写法增加间接层,影响逃逸分析,可能让本该栈分配的 slice 强制堆分配
真正该关注的:make 的参数顺序和容量陷阱
指针配合 make 的难点不在语法,而在理解「谁持有所有权」和「何时触发扩容」:
- 对
slice:第三个参数是容量,不是额外空间,make([]int, 2, 4)表示长度 2、容量 4;make([]int, 4, 2)编译报错 - 对
map:第二个参数是 hint(哈希桶预分配数),不是长度,make(map[int]int, 100)可减少 rehash 次数,但 map 仍为空 - 对
chan:第二个参数是缓冲区大小,make(chan int, 0)是无缓冲通道,make(chan int, 1)才能存 1 个值
这些细节一旦配错,会导致运行时 panic 或性能骤降——而指针只是表象,根源是没理清值语义和引用语义的边界。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










