new是通用内存分配器,仅分配零值内存并返回指针;make是slice、map、chan三种类型专用构造器,完成底层结构初始化并返回可用值。
make 和 new 的本质区别不是“初始化程度不同”,而是“职责完全不同”:new 是通用内存分配器,make 是三种特定类型的数据结构构造器。
new 只做一件事:分配零值内存并返回指针
它不关心类型语义,只管按字节大小申请一块堆内存(或逃逸后的栈),全部填 0,然后返回 *T。无论传 int、struct{} 还是 *[]int,它都照单全收,也都不做额外工作。
-
new(map[string]int) 返回*map[string]int,但解引用后仍是nil,(*m)["k"] = 1直接 panic -
new([]int)返回*[]int,*s是nil切片,len(*s) == 0,append(*s, 1)panic - 结构体字段含 slice/map/chan 时,
new(MyStruct)不会初始化这些字段——它们全为nil,必须手动对每个字段调用make
make 只服务三类:slice、map、chan,且必须完成结构就绪
它不是“分配 + 填零”,而是调用运行时专用逻辑,构建底层数据结构:切片要 header + 底层数组指针,map 要 hash 表 + bucket 数组,channel 要环形缓冲区 + 锁 + 等待队列。缺一不可。
-
make([]int, 5)→ 分配长度 5、容量 5 的底层数组,返回可下标访问的[]int -
make(map[string]int, 10)→ 预分配约 16 个 bucket(2 的幂),但不是精确容量,传太大纯浪费 -
make(chan int, 5)→ 创建带 5 元素缓冲区的 channel;传 0 或不传即无缓冲,收发必须同步 - 传错类型直接编译失败:
make(int, 5)、make(struct{}, 1)、make(*[]int)全报cannot make type ...
为什么不能混用?panic 不是偶然,是设计强制
Go 的类型系统在编译期就锁死了规则:make 的参数类型检查是硬性约束,new 的泛用性又不提供结构初始化能力。二者根本不在同一抽象层级。
- 写
m := new(map[string]int看似合法,但后续任何写操作都会触发assignment to entry in nil map - 写
s := new([]int)后试图(*s)[0] = 1,报index out of range—— 因为底层数组根本没分配 - 结构体里有
items []string字段时,&MyStruct{}比new(MyStruct)更安全:前者能顺手写&MyStruct{items: make([]string, 0, 16)}
真正容易被忽略的是:你声明的那个变量,是否“内部含需初始化的引用字段”——这种情况下,new 只是起点,make 才是必填动作。


















