




new返回指针,make返回引用类型本身;new(T)分配零值内存并返回*T,仅适用于任意类型;make仅适用于slice、map、chan,返回已初始化的实例。
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/receiveGo 类型系统对初始化方式做了硬性限制:
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 中不存在 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 是更安全、更符合直觉的选择。只有当你需要一个指向零值的指针(比如初始化 struct 字段、作为函数参数占位、或与 C 交互)时,才考虑 new。
make(make([]T, len)、make(map[K]V)、make(chan T, cap))&MyStruct{} 更清晰;new(MyStruct) 等价但易读性差var p *int = nil 或直接 nil,比 new(int) 更意图明确记住:Go 的设计哲学是“显式优于隐式”。make 明确表达了你要一个可工作的集合或通道;new 只表达“我要一块零值内存的地址”,这个需求本身就比较少见。