Go语言中 make 和 new 的区别是什么
make仅用于初始化切片、映射、通道,返回可直接使用的值;new返回指向零值的指针。若误用new初始化映射或切片会因空指针解引用而引发panic。结构体优先使用字面量初始化,需要指针时推荐使用&结构体名{},更直观且易读。正确区分使用可避免运行时错误。
先说一个核心判断:make 和 new 可不是随便换着用的。用错了,轻则 panic,重则运行时 nil 指针解引用。这根本不是风格差异,而是 Go 类型系统给你划下的硬杠杠。
哪些类型只能用 make?
简单来说,make 是专门给 slice、map、chan 这三个“亲儿子”用的。其他任何类型,比如 struct、[]int 的指针、*map[string]int,你传给 make,编译器直接翻脸,编译失败。
make([]int, 5)✅ 返回一个长度为 5、元素全为 0 的切片值,直接可用make(map[string]int)✅ 返回一个可直接m["k"] = 1赋值的 map 值make(chan int, 10)✅ 返回带缓冲区的 channel 值make(struct{X int})❌ 编译错误:cannot make type struct { X int }make(*[]int)❌ 编译错误:cannot make type *[]int
new 返回指针,make 返回值本身
这是两者最本质的区别。new(T) 永远返回 *T,一个指向 T 类型零值的指针;而 make(T, ...),只认那三种类型,返回的是 T 类型的值(不是指针),并且已经初始化好,拿过来就能用。
p := new(int)→p是*int,*p == 0s := make([]int, 3)→s是[]int,len(s) == 3,可直接s[0] = 1m := new(map[string]int)❌ 不合法:虽然语法上new允许,但它返回的是*map[string]int,一个指向 nil map 的指针。解引用后*m仍然是 nil,后续(*m)["k"] = 1必然 panic。
误用 new 初始化 map/slice/chan 的典型崩溃场景
很多新手会写 var m = new(map[string]int) 或 m := new(map[string]int),看着合法,但实际拿到的只是一个指向 nil map 的指针。结果就是,解引用后,你面对的还是 nil,啥也干不了。
m := new(map[string]int)→m类型是*map[string]int,*m == nil(*m)["x"] = 1→ panic: assignment to entry in nil map- 正确做法只有两种:要么
m := make(map[string]int)(要值),要么m := &map[string]int{}(先 make 再取地址,实际很少用) - 同理,
s := new([]int)得到的是*[]int,*s == nil,对*s调用append也会 panic。
结构体和自定义类型该用哪个?
对于结构体,make 肯定不行,new 也不是最佳选择。优先用字面量;需要指针时,&MyStruct{} 比 new(MyStruct) 更直观,而且还能顺手设置初始字段值。
s := MyStruct{Name: "a"}→ 值类型,栈上分配可达s := &MyStruct{Name: "a"}→ 指针,等价于new(MyStruct)+ 字段赋值,但写法更清晰new(MyStruct)→ 所有字段都是零值,无法指定初始值,语义弱了一截make(MyStruct)→ 编译报错:cannot make type MyStruct
一个容易被忽略的细节是:你写的变量是否「需要被外部修改」,或者内部是否「含有需要初始化的引用字段」——到这时候,通常得自己写 NewXXX() 函数,而不是依赖 new 或 make 来解决。


































