new只分配内存并返回零值指针,适用于非slice/map/chan类型;make专用于slice/map/chan,分配底层存储并初始化,返回可直接使用的值。

new 只分配内存,返回指针,且值为零值
当你写 new(int) 或 new(struct{a int}),Go 会为你在堆或栈上分配一块内存,把所有字段设成零值(0、""、nil),然后返回指向它的指针。它不关心类型内部结构是否“可用”,只管“有地址、有零值”。
- 适用于需要一个已分配内存的指针,但暂不初始化具体业务逻辑的场景,比如传参给函数要求接收
*T - 不能用于
slice、map、chan的实际使用——new([]int)返回的是一个*[]int,解引用后仍是[]int{}(长度容量均为 0,且底层数组为nil),后续append会 panic -
new(T)等价于var t T; &t,是语法糖,不是构造器,不调用任何初始化逻辑
make 只用于 slice/map/chan,返回可直接使用的值
make 不是通用内存分配器,它专为三种内建引用类型服务:它既分配底层存储(如数组、哈希桶、缓冲区),又完成类型特定的初始化,确保你拿到手就能用。
-
make([]int, 5)→ 返回长度为 5、元素全为0的切片,底层数组已分配 -
make(map[string]int)→ 返回一个空但可安全赋值的 map,内部哈希表结构已就绪 -
make(chan int, 10)→ 返回带 10 容量缓冲区的 channel,可立即收发,不会阻塞 - 传入非法类型(如
make(struct{})或make(*int))会在编译时报错:cannot make type struct {}
为什么 map/slice/chan 不能用 new 初始化?
因为它们是“描述性结构”:slice 是 header(指针+长度+容量),map 是运行时哈希表句柄,chan 是带状态的队列控制块。仅靠 new 分配一个零值 header 或 nil 句柄,等于只造了个空壳子,没建底座。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
var m map[string]int和m := new(map[string]int都导致m是nil,对它赋值 panic - 正确做法只有
m := make(map[string]int)或显式赋值m = map[string]int{}(后者本质也是调用 make) - 同理,
s := new([]int)得到的是*[]int,解引用后仍是不可 append 的 nil slice;而s := make([]int, 0)才得到可用 slice
初学者最容易踩的坑:混淆返回值类型和使用方式
最典型错误是看到 new 返回指针,就以为它能替代 make;或误以为 make 也返回指针,结果多套一层解引用。
-
make([]int, 5)返回[]int类型,直接用,别写*make(...) -
new(int)返回*int,必须解引用才能读写,new(int)本身不是整数 - 结构体字段含 map/slice 时,
new(Struct)只初始化结构体字段为零值(即字段 map 是 nil),需单独structField.Map = make(map[...]) - 性能上,
make对大容量 slice/map 建议指定 size(如make(map[int]int, 1000)),避免多次扩容;new无此参数,也不涉及扩容逻辑
真正要记住的其实就一条:需要立刻存取数据,就用 make;只需要一个干净的指针占位,且类型不是 slice/map/chan,才考虑 new。其余时候,直接字面量([]int{1,2}、map[string]int{"a": 1})更清晰。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










