new返回*T类型零值指针,make返回T类型已初始化引用值;slice/map/chan必须用make,结构体用new或&T{},不可用make。
new 返回的是指向零值的指针,类型为 *T;make 返回的是引用类型本身(非指针),类型为 T(如 []int、map[string]int、chan int)。试图用 make 初始化结构体或基本类型会编译失败。
new(int) → 返回 *int,值为 nil 指针指向的 0
make([]int, 5) → 返回 []int,底层数组已分配,长度为 5make(struct{a int}) → 编译错误:cannot make type struct { a int }
new([]int) → 返回 *[]int,但内部 slice header 仍为零值(nil),不能直接 append这三类类型在 Go 中是引用类型,底层由 header 结构(含指针、长度、容量等)描述。new 只分配 header 内存并清零,得到的是一个 nil 值;而 make 不仅分配 header,还初始化其字段,并为底层数组/哈希表/队列分配实际内存。
var m map[string]int = new(map[string]int) → m 是 *map[string]int,解引用后仍是 nil,for range m 或 m["k"] = 1 panicm := make(map[string]int) → m 是可用的空 map,可安全读写s := new([]byte) → 得到 *[]byte,*s == nil;s := make([]byte, 0) → 得到可 append 的空 slice当需要一个指向已初始化结构体的指针时,new(T) 等价于 &T{},但更简洁。它不调用任何构造逻辑,也不支持字段初始化。
type User struct {

ID int
Name string
}
u1 := new(User) // 等价于 &User{}
u2 := &User{} // 同上,语义更直观
u3 := &User{ID: 1} // ❌ new 无法做到字段赋值,只能靠 &T{...}
new(User) 安全、无副作用,适合初始化大型结构体指针&User{...},不能依赖 new
make 是语法错误,Go 不允许是否分配在堆上,取决于编译器逃逸分析,和用 new 还是 make 无直接关系。但行为模式会影响判断:
make([]int, 4))可能被分配在栈上(如果未逃逸)new(int) 分配单个整数,几乎总在栈上,除非该指针被返回或存储到全局变量make(map[int]int, 1000) 通常逃逸到堆,因为 map 底层哈希表结构复杂且需动态增长go tool compile -gcflags="-m" main.go 可验证具体分配位置别默认认为 new 更“轻量”——它只是语义不同,不是性能优化手段。