new只分配零值内存并返回指针,适用于所有具体类型;make专为[]T、map[K]V、chan T设计,返回已初始化的可用值,二者不可互换,误用将panic。

new 不是创建对象的推荐方式,它只做一件事:分配零值内存并返回指针。绝大多数场景下,你应该用 &T{} 或 make,而不是 new。
什么时候必须用 new?
只有在泛型函数中需要获取任意类型的零值指针时,new 才不可替代。比如:
func NewPtr[T any]() *T {
return new(T)
}
这种写法能统一处理 int、string、自定义结构体等类型,且保证返回非 nil 指针(哪怕 T 是 []byte,也返回 *[]byte,值为 nil,但指针本身有效)。
-
new不能用于接口类型(new(interface{})编译失败) - 传入的类型必须是具体类型,不能是未定义的别名(如
type MyInt int后直接new(MyInt)是合法的,但若别名未声明则报错) - 它不触发任何字段初始化逻辑——哪怕结构体里有
time.Time字段,也只会是零时间,不会调用其内部构造
new(MyStruct) 和 &MyStruct{} 的实际差异
两者都返回 *MyStruct,字段都是零值,但语义和可扩展性不同:
-
new(MyStruct)更“机械”:纯粹分配 + 零值,无法同时设置字段 -
&MyStruct{Field: "x"}可立即初始化部分字段,更贴近意图 - 如果结构体字段含引用类型(如
map[string]int),两者都只给该字段赋零值(即nil),后续仍需手动make,否则解引用 panic
错误示例:
立即学习“go语言免费学习笔记(深入)”;
s := new(MyStruct) s.Data["key"] = 42 // panic: assignment to entry in nil map
对 slice/map/chan 使用 new 会怎样?
new([]int) 返回的是 *[]int,其值为 nil;不是空切片,是 nil 指针。你不能直接 append、len 或 range 它。
-
new([]int)→ 得到*[]int,解引用后是nil -
new(map[string]int) → 得到*map[string]int,解引用后是nil,不能delete或赋值 -
new(chan int)→ 得到*chan int,解引用后是nil,不能send或recv - 这些类型必须用
make初始化,new对它们毫无实用价值
为什么你几乎从不需要 new?
Go 中没有构造函数,但惯用做法是封装成 NewXXX 工厂函数,例如:
func NewPerson(name string, age int) *Person {
return &Person{Name: name, Age: age}
}
这种写法比 new(Person) + 逐字段赋值更安全、更清晰、更易测试。而 new 唯一优势——泛型中统一获取零值指针——恰恰是它最常被误用的地方:很多人在非泛型上下文中硬套 new,只为“看起来像初始化”,结果反而掩盖了真实意图。
真正容易被忽略的点是:new 返回的永远是指针,但它不保证所指内容“可用”;是否可用,取决于类型本身是否支持零值直接使用——比如 *os.File 零值是无效的,*sync.Mutex 零值却是合法的。这个边界,得靠人来判断,编译器不管。


















