new只分配内存不初始化引用类型,make专用于slice/map/chan的完整初始化;new返回指针且值为零,make返回可直接使用的非nil值。

new 只分配内存,不初始化引用类型
用 new 创建 map、slice 或 chan 会得到一个 nil 值,直接使用必然 panic。比如 new(map[string]int) 返回的是 *map[string]int,但解引用后仍是 nil map,往里写键值会触发 panic: assignment to entry in nil map。
常见错误场景:
- 误以为
new([]int)能返回可用切片,结果len(*s) == 0且底层数组未分配,append前必须先解引用再赋值,逻辑冗余且易错 - 在函数参数中传
*map并期望调用方用new初始化,实际接收的是 nil 指针,后续操作全崩
根本原因:map/slice/chan 是引用类型,其零值本身就是 nil;new 只做内存分配+零值填充,不会触发它们内部结构(如哈希表、底层数组、缓冲区)的构造。
make 专用于 slice/map/chan 的完整初始化
make 不是通用分配器,它只接受三种类型,并在分配内存的同时完成底层数据结构的构建。返回值就是可直接使用的值,不是指针。
立即学习“go语言免费学习笔记(深入)”;
关键差异点:
-
make([]int, 5)→ 分配长度为 5、容量为 5 的底层数组,返回可读写的切片 -
make(map[string]int)→ 分配哈希桶、初始化哈希表,返回非 nil 的 map -
make(chan int, 10)→ 分配带 10 容量缓冲区的 channel,发送不会立即阻塞
注意参数差异:make 对 slice 支持两个或三个参数(make([]T, len) 或 make([]T, len, cap)),对 map 可选容量参数(make(map[K]V, hint)),对 chan 可选缓冲大小(make(chan T, buffer))。传错数量或类型会编译报错。
new 适合基本类型和结构体的指针初始化
当需要一个指向零值的指针,且后续会显式赋值时,new 简洁可靠。它等价于 var t T; &t,是语法糖。
典型用法:
-
p := new(int)→ 得到*int,*p初始为0,适合传参或延迟赋值 -
s := new(StructType)→ 返回*StructType,字段全为零值,可安全访问字段(如s.Field = val) - 与复合字面量对比:
&StructType{}效果相同,但new更明确表达“仅需零值”意图
性能上无差别,但 new 不适用于需要非零初始字段的结构体——它不做字段级初始化,只能靠后续赋值或用字面量。
混淆使用会导致运行时 panic 或语义错误
最典型的坑是把 new 和 make 当成可互换的“分配函数”。例如:
- 写
m := new(map[string]int然后*m["k"] = v→ 编译失败(invalid operation: cannot index),因为*m是 map 类型,不能对 map 类型取下标 - 写
s := new([]int)然后s = &append(*s, 1)→ 逻辑绕远,且每次append都可能重新分配,s指针失效 - 用
make初始化 struct → 编译错误:cannot make type StructType
Go 的类型系统会在编译期拦截多数误用,但 nil 引用类型的运行时 panic(如 nil map 写入)仍需警惕。真正容易被忽略的是:即使你没手动写 new 或 make,var m map[string]int 这种声明本身也等价于 new 的效果(零值 nil),必须显式 make 才能用。


















