new只分配零值内存并返回指针,适用于所有类型;make专为[]t、map[k]v、chan t服务,返回已初始化的可用值——二者不能互换,选错会panic。

别拿 make 和 new 比“谁更快”——它们根本不在同一层面上做事情,强行对比只会误导你优化方向。
用错函数会导致编译失败,而不是性能变差
Go 编译器会直接拒绝非法组合:make 只接受 []T、map[K]V、chan T 三种类型;对结构体或基础类型调用 make,报错信息是 cannot make type xxx。new 则禁止用于这三类引用类型,否则报 cannot use new on type xxx。这不是运行时开销问题,是语法红线。
-
new(int)合法;make(int, 1)❌ 编译失败 -
new(map[string]int)❌ 编译失败;make(map[string]int)✅ -
new([]byte)合法(返回*[]byte,但几乎没用);make([]byte, 10)✅(返回可直接用的 slice)
逃逸分析决定分配位置,不是函数名本身
是否分配到堆上,取决于变量是否“逃逸”出当前作用域,跟你是写 new 还是 make 没有直接因果关系。但行为模式会影响编译器判断:
-
new(int)返回指针,若该指针被返回、存入全局变量或传给 goroutine,int必然逃逸到堆 -
make([]int, 4)若 slice 未逃逸(比如只在函数内遍历),底层数组可能分配在栈上;但make([]int, 1000)几乎必然逃逸 -
make(map[string]int)总是逃逸——map 底层哈希表结构复杂,必须动态管理,无法栈分配
验证方式:加 go tool compile -gcflags="-m" main.go 看输出里有没有 move to heap。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
初始化语义差异比性能更关键
new(T) 只做一件事:分配零值内存,返回 *T;make 是初始化操作,返回的是可用对象本身:
-
s := make([]int, 5)→ 得到长度为 5、元素全为 0 的 slice,可直接s[0] = 1 -
s := new([]int)→ 得到*[]int,其值为&[]int(nil),解引用后仍是 nil slice,(*s)[0] = 1panic -
m := make(map[string]int)→ 可直接m["k"] = 1 -
m := new(map[string]int)→ 得到*map[string]int,其值为&map[string]int(nil),解引用后仍是 nil map,(*m)["k"] = 1panic
这个区别不是快慢问题,是“能不能跑起来”的问题。
实际选型建议:按类型和用途硬匹配
不用纠结哪个“更轻量”,直接查类型:
- 要初始化
[]T、map[K]V、chan T→ 无条件用make - 要获取一个指向零值的指针(比如传参需要
*T,且不希望字段赋初值)→ 用new(T) - 想初始化结构体并设字段 → 用字面量
&T{Field: val},不是new,更不是make - 分配单个基础类型指针(如
*int)→new(int)或直接func() *int { i := 0; return &i }(),后者更常见
真正容易被忽略的点是:很多人以为 new 更“底层”所以更高效,但实际中它极少出现——绝大多数场景下,&T{} 或直接声明变量更自然,而 make 是那三个类型唯一合法的初始化入口。性能瓶颈从来不在这里,而在逃逸导致的 GC 压力或底层数组/哈希表的扩容逻辑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










