new是堆上分配零值内存并返回指针的操作,不调用构造函数、不初始化字段(仅零值)、不支持自定义逻辑;它与make不同,后者用于slice/map/channel且返回值而非指针。

new 是什么,不是什么
new 只做一件事:在堆上分配零值内存,并返回指向它的指针。它不调用构造函数,不初始化字段(除了零值),也不支持自定义逻辑。你写 new(int),得到的是一个指向 0 的 *int;写 new(bytes.Buffer),得到的是一个所有字段都是零值的 *bytes.Buffer——但这个实例**不能直接用**,因为 bytes.Buffer 的内部字段(比如 buf 切片)虽为 nil,但后续 Write 等方法会 panic。
什么时候该用 new,什么时候不该用
绝大多数时候不该用 new。Go 里更自然、更安全的方式是字面量 + 取地址:
-
&struct{a int}{a: 42}比new(struct{a int})后再赋值更清晰 - 对于有非零初始需求的类型(如
sync.Mutex),必须用字面量或构造函数:var m sync.Mutex或new(sync.Mutex)都能过编译,但后者返回的互斥锁处于未初始化状态,Lock()会 panic - 只有极少数场景下
new不可替代:比如泛型函数中需要为任意类型分配零值指针,且无法用结构体字面量(类型未知)
new 和 make 的关键区别
这是最常混淆的点:new(T) 返回 *T,make(T, args...) 返回 T(仅适用于 slice/map/channel)。它们完全不重叠:
-
new([]int)→ 返回*[]int,即一个指向 nil 切片的指针,解引用后仍是 nil -
make([]int, 5)→ 返回一个长度为 5、元素全为 0 的切片值 - 对 map 使用
new(map[string]int) 得到的是*map[string]int,但这个指针指向的 map 本身还是 nil,直接*p["k"] = 1会 panic - 对 channel 同理:
new(chan int)返回一个指向 nil channel 的指针,发送/接收都会阻塞或 panic
容易被忽略的坑:指针类型和零值语义
用 new 分配指针类型时,结果可能不是你想要的零值:
立即学习“go语言免费学习笔记(深入)”;
-
new(*int)返回的是**int,其值是nil(即指向 nil 的指针),而不是一个指向0的*int - 嵌套结构体字段若为指针类型,
new不会递归初始化它们,只会设为nil—— 这和 JSON 解析或 ORM 映射时的“默认空值”行为不一致,容易导致空指针 dereference - 如果函数签名要求
*T且你传了new(T),看起来没问题,但调用方可能隐含“该指针已就绪”的假设,而实际上内部资源(如 io.ReadCloser 的底层 buffer)并未准备
真正要小心的,从来不是语法能不能写通,而是那个零值指针背后有没有人等着它干活。










