new(t)只分配零值内存并返回*t指针,不初始化引用字段、不调用构造逻辑;对结构体效果同&t{}但语义更严格,泛型中唯一支持任意类型,大对象分配有oom风险。

new(T) 分配结构体时到底做了什么
它只做两件事:申请足够存下 T 的内存块,然后把整块内存填成零值,最后返回 *T。不调用任何构造逻辑,不初始化内部字段的引用类型(比如 struct 里的 map[string]int 字段仍是 nil),也不触发任何方法。
常见错误现象:panic: assignment to entry in nil map,就因为写了 p := new(MyStruct),而 MyStruct 里有个 data map[string]int 字段——p.data 是 nil,不能直接 p.data["k"] = 1。
-
new(Person)和&Person{}底层行为一致,都返回指向零值内存的*Person - 但语义不同:
new(Person)强制所有字段为零值;&Person{Name: "A"}可部分初始化,更清晰、更常用 - 若
T是基本类型(如int、[4]byte),&T{}不合法,new(T)是唯一选择
为什么 new(struct{}) 能用,但 new([]int) 不能 append
因为 new([]int) 返回的是 *[]int,解引用后是 nil,不是空切片;而 append 要求操作对象有底层数组,nil 切片没有——所以一调就 panic。
对比:
-
s := new([]int)→*s是nil,append(*s, 1)直接崩溃 -
s := make([]int, 0)→s是有效切片,len(s)==0但cap(s)>=0,可安全append -
s := []int{}→ 等价于make([]int, 0),也是可用切片
同理,new(map[string]int) 返回 *map[string]int,其值为 nil,不能 range 或赋值;必须用 m := make(map[string]int)。
泛型函数里为什么只能用 new(T)
当你写一个通用函数,想为任意类型 T 返回一个零值指针时,&T{} 编译不过——T 可能不是结构体(比如 T=int 或 T=[]byte),Go 不允许对非结构体类型使用复合字面量。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
示例:
func NewPtr[T any]() *T {
return new(T)
}
这个函数对 int、struct{}、[8]byte 都有效;但若 T 是接口类型(如 io.Reader),new(T) 会编译失败——接口不能直接分配内存。
注意:new(T) 返回的指针所指内容永远是零值,不触发任何自定义初始化,也不区分栈/堆——逃逸分析决定分配位置。
new 大数组或大结构体时容易忽略的开销
new([1000000]int) 会立即在堆上分配约 8MB 连续内存(64 位系统),和 make(chan int, 1000000) 类似,属于“预分配大户”。它不懒加载,不按需扩容,一旦调用就全量分配。
性能影响:
- 小对象(≤16KB)走 mcache span 缓存,延迟低
- 大对象直走堆,可能触发 GC 扫描,也可能导致页分配抖动
- 若该内存后续没被实际使用,就是纯浪费;逃逸分析无法优化掉这种显式分配
真正容易被忽略的点:你写 new(MyBigStruct) 时,哪怕结构体里只有 1 个字段用到了,整个结构体的零值内存仍会被完整分配——没有“按需填充”这回事。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










