new 返回指向类型 T 零值的指针,仅分配内存、清零并返回地址,不初始化;适用于泛型、反射等需零值指针的底层场景,日常开发中应优先使用 &T{} 或 make。

Go 的 new 函数确实返回指针,但仅限于“指向零值的指针”
是的,new 的返回值类型永远是 *T —— 一个指向类型 T 零值的指针。它不做任何额外初始化,不调用方法,不构造底层数组或哈希表,只干三件事:分配内存、清零、返回指针地址。
-
new(int)→ 返回*int,值为0(不是未定义,是确定的零值) -
new(string)→ 返回*string,解引用后是"" -
new([]int)→ 返回*[]int,解引用后是nil切片(⚠️不能直接append) -
new(map[string]int)→ 返回*map[string]int,解引用后是nilmap(⚠️不能直接赋值,会 panic)
什么时候该用 new?多数时候其实不该用
new 的适用场景非常窄。它不是“创建对象”的常规手段,而是为特定需求服务的底层工具:
- 需要一个明确指向零值的指针,且类型太复杂写
&T{}太冗长(比如new([1024]byte)或嵌套泛型类型) - 在泛型函数中,类型
T在编译期未知,无法用字面量构造,只能靠new(T) - 反射场景下需分配零值内存并获取指针(如
reflect.New内部就调用new) - 你正在写运行时或内存分析相关代码,需要显式控制零值分配路径
日常开发中,&MyStruct{} 更直观,make([]int, 0) 更安全,new 很少是最佳选择。
new 和 make 混用会出什么错?
最典型的问题是误以为 new([]int) 能得到一个可用切片:
立即学习“go语言免费学习笔记(深入)”;
slicePtr := new([]int) // *slicePtr 是 nil!下面这行会 panic: // append(*slicePtr, 1)
而 make 返回的是值本身,不是指针:
-
new([]int)→ 类型是*[]int,值为nil -
make([]int, 5)→ 类型是[]int,值为长度 5、容量 5 的切片 - 想获得“可 append 的切片指针”,应写
s := make([]int, 0); ptr := &s,而非new([]int)
为什么函数里能安全返回局部变量的指针,却不用 new?
因为 Go 编译器的逃逸分析会自动把“需要被外部访问的局部变量”分配到堆上。所以像 func NewInt(v int) *int { return &v } 是完全合法且高效的 —— 它比 new(int) 后再赋值更直接:
-
new(int):分配 → 清零 → 返回指针 → 再赋值(两步) -
&v(逃逸后):分配(带初值)→ 返回指针(一步)
这也是为什么标准库几乎不用 new:构造函数如 bytes.NewBuffer、sync.Pool.Get 等,都直接返回带初值的指针,而不是先零值再填充。
真正容易被忽略的点是:new 不解决“初始化逻辑”,它只是内存分配的起点;而绝大多数业务代码要的不是“零值指针”,而是“已初始化的对象指针”。别让语法糖掩盖了语义意图。










