new只分配零值内存并返回指针,不初始化引用字段、不支持slice/map/chan可用实例;对[]int用new后append会panic,因其解引用为nil,而append要求非nil底层数组。

Go 的 new 函数只做一件事:分配一块指定类型的零值内存,并返回指向它的指针;它不初始化引用字段,不调用任何逻辑,也不支持 slice/map/chan 的可用实例构造——选错场景直接 panic。
为什么对 []int 用 new 后 append 就崩溃
因为 new([]int) 返回的是 *[]int,其解引用后是 nil,不是空切片([]int{})。Go 的 append 要求操作对象是非 nil 的底层数组,否则触发 panic: invalid memory address or nil pointer dereference。
-
new([]int)→ 得到*[]int,值为nil -
*new([]int)→ 解引用后仍是nil,不能传给append - 正确做法是:
s := make([]int, 0),或需要指针时写&s - 同理,
new(map[string]int)返回*map[string]int,其值为nil,无法直接range或赋值
new 和 &T{} 在结构体上效果相同,但语义和灵活性不同
两者都分配零值内存并返回 *T,底层行为一致,但写法意图差异明显:
-
new(T)强制所有字段为零值,无法指定任何初始值 -
&T{Field: 42}可部分初始化,未写的字段仍为零值,代码更清晰、更符合 Go 习惯 - 当
T是基本类型(如int、bool)时,&T{}不合法,new(T)是唯一选择 - 若
T含map/slice字段,二者都只设为nil,不会自动make—— 这点常被忽略
泛型函数里为什么必须用 new
当你写一个通用函数,想为任意类型 T 返回一个零值指针时,&T{} 编译不过(T 可能不是结构体),而 new(T) 是唯一合法且安全的方式:
func NewPtr[T any]() *T {
return new(T)
}
- 该函数对
int、struct{}、[4]byte都有效 - 但若
T是接口类型(如io.Reader),new(T)编译失败 —— 接口本身不能直接分配内存 - 注意:返回的指针所指内容永远是零值,不触发任何构造逻辑(比如自定义初始化函数)
new 的内存分配路径和性能影响
new(T) 最终调用 runtime.mallocgc(T.size, T, true),走的是 Go 的标准堆分配路径。小对象(≤16KB)优先从 mcache 的 span 缓存中分配,大对象直走堆;是否逃逸由编译器逃逸分析决定,与写法无关。
- 性能开销几乎可忽略,但可读性上,
&T{}更贴近意图,new(T)应视为“不得已而用之” - 它不区分栈/堆 —— 分配位置由逃逸分析决定,不是语法控制的
- 没有 GC 特殊标记,分配的内存和普通堆对象一样,仅在无引用时被回收
- 容易被忽略的一点:
new([1000000]int)会立即分配 8MB(64 位)连续内存,和make(chan int, 1000000)类似,属于“预分配大户”,需警惕 OOM
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











