new返回指针,make返回引用类型本身;new(T)分配零值内存并返回*T,仅适用于任意类型;make仅适用于slice、map、chan,返回已初始化的实例。

new 返回的是指针,make 返回的是引用类型本身
new 和 make 都用于内存分配,但语义完全不同:new(T) 为类型 T 分配零值内存,并返回 *T;make 只适用于 slice、map、chan,返回的是这些类型的“实例”,不是指针。
常见错误是试图用 new([]int) 得到一个可直接 append 的切片——它返回 *[]int,即指向切片头的指针,而非切片本身,后续调用 append 会编译失败或行为异常。
-
new(int)→ 返回*int,值为nil指针(指向一个值为 0 的 int) -
make([]int, 3)→ 返回[]int,底层已分配长度为 3 的数组,可直接使用 -
new(map[string]int)是非法的:编译报错cannot use new(map[string]int) (value of type *map[string]int) as map[string]int value -
make(chan int)返回chan int;new(chan int)返回*chan int,后者不能用于 select 或 send/receive
哪些类型只能用 make,哪些只能用 new
Go 类型系统对初始化方式做了硬性限制:
- 只有
slice、map、chan能用make;其他任何类型(包括自定义 struct、array、interface)都不能用make -
new可用于任意类型,但对引用类型(如map、slice、chan)没意义——因为它们本身是描述符(header),零值已是有效空状态(如nil map),无需额外分配指针包装 -
func、unsafe.Pointer、interface{}等不能用make,也不能用new初始化出可用实例(函数需字面量,interface 需赋值具体类型)
例如:new([]byte) 返回 *[]byte,但它指向的 []byte 仍是 nil,无法直接写入;而 make([]byte, 10) 返回的 []byte 已具备底层数组和长度容量信息。
立即学习“go语言免费学习笔记(深入)”;
指针 vs 引用类型:Go 里没有“引用传递”,只有“传值”
Go 中不存在 C++ 风格的引用类型(&T 不是类型,而是取地址操作符)。所谓“引用类型”(slice/map/chan/func)只是内置类型的别称,它们的变量本身是值——但该值包含指针字段,指向底层数据结构。
这意味着:
- 把一个
map变量赋给另一个,是复制其 header(含指针、len、cap 等),两个变量仍指向同一份底层哈希表 - 把一个
*struct传入函数,函数内修改(*s).Field会影响原值,因为解引用后操作的是同一块内存 - 但
new出来的*map或*slice是多余且危险的:你得先解引用才能用,还容易忘记初始化内部字段
典型反模式:
var m *map[string]int = new(map[string]int) *m["key"] = 42 // panic: assignment to entry in nil map因为
new(map[string]int) 返回的是 *map[string]int,其指向的 map 本身仍是 nil。
实际编码中该选哪个:优先 make,避免 new(除非明确需要指针)
绝大多数场景下,make 是更安全、更符合直觉的选择。只有当你需要一个指向零值的指针(比如初始化 struct 字段、作为函数参数占位、或与 C 交互)时,才考虑 new。
- 初始化切片/映射/通道:无条件用
make(make([]T, len)、make(map[K]V)、make(chan T, cap)) - 需要一个未初始化的 struct 指针(如作为方法接收者或避免拷贝大对象):用
&MyStruct{}更清晰;new(MyStruct)等价但易读性差 - 测试中模拟空指针输入:
var p *int = nil或直接nil,比new(int)更意图明确
记住:Go 的设计哲学是“显式优于隐式”。make 明确表达了你要一个可工作的集合或通道;new 只表达“我要一块零值内存的地址”,这个需求本身就比较少见。










