如何在Golang中使用new与make_Golang内存分配差异解析

12次阅读

new返回*T类型零值指针,make返回T类型已初始化引用值;slice/map/chan必须用make,结构体用new或&T{},不可用make。

如何在Golang中使用new与make_Golang内存分配差异解析

new 和 make 都返回指针,但类型完全不同

new 返回的是指向零值的指针,类型为 *Tmake 返回的是引用类型本身(非指针),类型为 T(如 []intmap[String]intchan int)。试图用 make 初始化结构体或基本类型会编译失败。

  • new(int) → 返回 *int,值为 nil 指针指向的 0
  • make([]int, 5) → 返回 []int,底层数组已分配,长度为 5
  • make(Struct{a int})编译错误cannot make type struct { a int }
  • new([]int) → 返回 *[]int,但内部 slice header 仍为零值(nil),不能直接 append

slice、map、chan 必须用 make,不能用 new

这三类类型在 go 中是引用类型,底层由 header 结构(含指针、长度、容量等)描述。new 只分配 header 内存并清零,得到的是一个 nil 值;而 make 不仅分配 header,还初始化其字段,并为底层数组/哈希表/队列分配实际内存。

  • var m map[string]int = new(map[string]int)m*map[string]int,解引用后仍是 nilfor range mm["k"] = 1 panic
  • m := make(map[string]int)m 是可用的空 map,可安全读写
  • s := new([]byte) → 得到 *[]byte*s == nils := make([]byte, 0) → 得到可 append 的空 slice

new 适合快速获得零值指针,尤其用于结构体

当需要一个指向已初始化结构体的指针时,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 都可能触发分配

是否分配在堆上,取决于编译器逃逸分析,和用 new 还是 make 无直接关系。但行为模式会影响判断:

立即学习go语言免费学习笔记(深入)”;

  • 小 slice(如 make([]int, 4))可能被分配在上(如果未逃逸)
  • new(int) 分配单个整数,几乎总在上,除非该指针被返回或存储到全局变量
  • make(map[int]int, 1000) 通常逃逸到堆,因为 map 底层哈希表结构复杂且需动态增长
  • go tool compile -gcflags="-m" main.go 可验证具体分配位置

别默认认为 new 更“轻量”——它只是语义不同,不是性能优化手段。

text=ZqhQzanResources